0

Send Message via Webhook

by
Published today

Post a text and/or card message to a Google Chat space through its incoming webhook URL, optionally in a thread.

Script gchat Verified

The script

Submitted by hugo989 Typescript (fetch-only)
Verified 1 day ago
1
//native
2

3
/**
4
 * Send Message via Webhook
5
 * Post a message to a Chat space through its incoming webhook, as the webhook (no OAuth connection or Chat app needed). Send `text` (Chat markup: `*bold*`, `_italic_`, `<users/123>` mentions), `cards_v2` (a list of `{ cardId, card }` objects), or both. Set `thread_key` to group messages into a thread; `message_reply_option` picks whether a missing thread is created (REPLY_MESSAGE_FALLBACK_TO_NEW_THREAD, the default when a key is set) or the message fails (REPLY_MESSAGE_OR_FAIL). Google allows 1 request per second per space, shared by all its webhooks.
6
 */
7
export async function main(
8
  auth: RT.GchatWebhook,
9
  text: string | undefined,
10
  cards_v2: { [key: string]: any }[] | undefined,
11
  thread_key: string | undefined,
12
  message_reply_option:
13
    | "REPLY_MESSAGE_FALLBACK_TO_NEW_THREAD"
14
    | "REPLY_MESSAGE_OR_FAIL"
15
    | undefined
16
) {
17
  if (!text && !cards_v2?.length) {
18
    throw new Error("Set text, cards_v2 or both")
19
  }
20
  if (message_reply_option && !thread_key) {
21
    throw new Error("message_reply_option needs a thread_key")
22
  }
23
  const url = new URL(auth.url)
24
  const body: { [key: string]: any } = {
25
    text: text || undefined,
26
    cardsV2: cards_v2?.length ? cards_v2 : undefined,
27
  }
28
  if (thread_key) {
29
    body.thread = { threadKey: thread_key }
30
    url.searchParams.set(
31
      "messageReplyOption",
32
      message_reply_option || "REPLY_MESSAGE_FALLBACK_TO_NEW_THREAD"
33
    )
34
  }
35

36
  const response = await fetch(url, {
37
    method: "POST",
38
    headers: {
39
      "Content-Type": "application/json; charset=UTF-8",
40
      Accept: "application/json",
41
    },
42
    body: JSON.stringify(body),
43
  })
44
  if (response.status === 429) {
45
    const retry = response.headers.get("Retry-After")
46
    throw new Error(
47
      `429 rate limited: Google Chat allows 1 request per second per space, shared by all its webhooks${
48
        retry ? `; retry after ${retry}s` : ""
49
      }. ${await response.text()}`
50
    )
51
  }
52
  if (!response.ok) {
53
    throw new Error(`${response.status} ${await response.text()}`)
54
  }
55

56
  return await response.json()
57
}
58