Reading a Channel
How to read a channel's messages with an incoming webhook's URL and secret — enabling, request, response, paging, errors
A tool that posts through an incoming webhook can also read that channel's messages with the same URL and secret. For example, a deploy script can check for an approval reply in the channel, or an agent can read and summarize recent conversation. Reading must be allowed per webhook. Posting is covered in Incoming Webhooks.
Allowing reads
Turn on Allow reading channel messages when you create the webhook, or for an existing webhook turn it on from the ⋯ menu in Manage webhooks. Only channel admins can change it. Turning it off blocks reads immediately. Posting and the URL and secret are unaffected.
Once reads are allowed, the secret alone can read that channel's conversation. Do not turn it on for tools that only send notifications. If the secret leaks, delete the webhook and create a new one.
Request format
| Item | Value | Required |
|---|---|---|
| Method | GET | Yes |
| URL | https://collabops.ai/api/v2/integration/webhook/<token>/messages | Yes |
Authorization header | Bearer <secret> (the same value used for posting) | Yes |
Query
| Name | Required | Description |
|---|---|---|
since | Yes | Read from this time (inclusive). An ISO 8601 time with a time zone, or unix seconds. |
until | No | Read up to this time (exclusive). Defaults to now. At most 7 days after since. |
limit | No | Messages per call. 1 to 100. |
after | No | For the next page, the next_after_cursor value from the previous response. |
curl -G "https://collabops.ai/api/v2/integration/webhook/<token>/messages" \
-H "Authorization: Bearer <secret>" \
--data-urlencode "since=2026-10-12T09:00:00+09:00" \
--data-urlencode "limit=50"The + in +09:00 is read as a space in a query string. Send it with --data-urlencode as above or write it as %2B. Unix seconds avoid the problem.
Response
You get 200 with the channel's messages. Thread replies are not listed; the parent's reply_count shows how many there are. Reading does not mark anything as read.
{
"messages": [
{
"id": "01a12efa-1da6-75f1-b4e2-6d3349b44b8e",
"parent_message_id": null,
"type": "user",
"created_at": "2026-10-12T07:18:25.958881Z",
"edited_at": null,
"deleted_at": null,
"reply_count": 1,
"blocks": [
{
"id": "054968bf-26fa-490e-968e-49f29f85bb44",
"type": "paragraph",
"parentId": null,
"attrs": null,
"children": [{"text": "Nightly batch started", "marks": [{"type": "bold"}]}]
}
],
"author": {
"user_id": "37b6a1ef-35c3-454b-b610-929e5fc99384",
"full_name": "Deploy alerts",
"email": "37b6a1ef-35c3-454b-b610-929e5fc99384@hooks.collabops.bot"
}
}
],
"has_more": true,
"next_after_cursor": "01a12efa-1da6-75f1-b4e2-6d3349b44b8e"
}| Field | Description |
|---|---|
messages | Array of messages. Pages advance from the oldest part of the range, but the order within a page is not defined, so sort by created_at. |
has_more | true if the same range has more messages. |
next_after_cursor | The value to pass as after for the next page. null when there is none. |
A message
| Field | Description |
|---|---|
id | Message ID. |
parent_message_id | For a thread reply, the parent's message ID. Replies are not listed today, so this is always null. |
type | user for messages written by people and bots, system for notices such as members being added. system messages have null blocks. More values may be added, so skip values you do not recognize. |
created_at · edited_at | When it was written and last edited (UTC). |
deleted_at | When it was deleted, for deleted messages. blocks is then null. |
reply_count | Number of thread replies. |
blocks | The body, in the same shape as the incoming webhook blocks format, with empty fields sent as null. You can send it back as is. See the Message Format Reference. |
author | The author's user_id · full_name · email. For messages posted by a webhook you get the webhook name and a bot-only address. null if not found. |
Reactions and attachments are not included.
Getting the next page
When has_more is true, call again with the same since and until plus next_after_cursor as after. If you leave out until, "now" moves with every call, so when reading several pages set until from the first request to fix the range.
# First page — fix the range
SINCE="2026-10-12T09:00:00+09:00"
UNTIL="2026-10-12T18:00:00+09:00"
curl -sS -G "https://collabops.ai/api/v2/integration/webhook/<token>/messages" -H "Authorization: Bearer <secret>" \
--data-urlencode "since=$SINCE" --data-urlencode "until=$UNTIL" > page1.json
# Next page — same since and until, plus after
AFTER=$(sed -n 's/.*"next_after_cursor":"\([^"]*\)".*/\1/p' page1.json)
curl -sS -G "https://collabops.ai/api/v2/integration/webhook/<token>/messages" -H "Authorization: Bearer <secret>" \
--data-urlencode "since=$SINCE" --data-urlencode "until=$UNTIL" \
--data-urlencode "after=$AFTER" > page2.jsonFor periods longer than 7 days, read in consecutive 7-day windows.
Error responses
Error bodies have the same shape as for posting (Incoming Webhooks — Error responses). Use the reason in error.title to tell causes apart.
| Status | When | What to do |
|---|---|---|
| 401 | The secret is wrong, the webhook is turned off, or reads are not allowed. When reads are not allowed, error.title ends with read not allowed. | Fix the secret, or turn on the webhook or reads. |
| 403 | The webhook's channel cannot be read (for example, it was deleted) | Check the channel. |
| 404 | No webhook matches the token in the URL | Use the URL of a newly created webhook. |
| 422 | since is missing or malformed, since is later than until, the range is longer than 7 days, or limit is outside 1 to 100 | Fix the query. |
| 429 | More than 10 calls per minute for one webhook. Counted separately from the posting limit (60 per minute). | Wait the number of seconds in the Retry-After header, then call again. |
| 503 · 502 · 504 | A temporary internal error or a slow response | Call again after a short wait. |
Read requests are not recorded in Delivery history.