中文

Teams Notification Channel

One HTTP call sends a message to a colleague's Teams — as a direct message or into a group chat. You don't touch Teams, Graph, or Bot Framework, you don't request Azure permissions, and you don't run a bot of your own.

Request / manage my API key →
Contents

What this is

The company's shared outbound channel for Teams notifications. Messages are delivered by a bot called AlertBot, so the recipient sees a DM from AlertBot, or a bot message in a group chat. It fits anything where a system needs to reach a person: release notices, alerts, approval reminders, due-date nudges.

Step 1: get an API key

Open the admin portal, sign in with your company Microsoft account, and submit a request (short client id, app name, purpose). Once an admin approves it, the key is sent to you as a Teams DM — you can also come back to the portal and click “Reveal key” to see it once.

The key is shown only once. Put it straight into your secret manager (AWS Secrets Manager / CI secret / environment variable). Don't hardcode it and don't commit it. If you lose it, you don't need to ask anyone — rotate it yourself in the portal and the old key stops working immediately.

The portal also shows which clients you own, where each request stands, the key's prefix, and lets you withdraw a request that hasn't been approved yet.

Send to a person (DM)

POST /send
Authorization: Bearer <your API key>
Content-Type: application/json

{"to": "someone@lofty.com", "text": "Build #1234 shipped ✅"}

curl

curl -sS -X POST "$NOTIFY_URL/send" \
  -H "Authorization: Bearer $NOTIFY_KEY" \
  -H "Content-Type: application/json" \
  -d '{"to":"someone@lofty.com","text":"Build #1234 shipped ✅"}'

Python (standard library only)

import json, os, urllib.request

def notify(to, text):
    req = urllib.request.Request(
        os.environ["NOTIFY_URL"] + "/send",
        data=json.dumps({"to": to, "text": text}).encode(),
        headers={"Authorization": "Bearer " + os.environ["NOTIFY_KEY"],
                 "Content-Type": "application/json"},
    )
    with urllib.request.urlopen(req, timeout=20) as r:
        return json.load(r)

Success response

{"ok": true, "to": "someone@lofty.com", "toKind": "user",
 "displayName": "Someone", "chatId": "19:...@unq.gbl.spaces",
 "messageId": "1699...", "requestId": "21ddaecf-..."}

Keep the requestId — hand it to the platform owner and they can look up exactly that call in the audit log.

Send to a group chat

Group chats use a separate endpoint, and the recipient field is chat_id:

POST /send/group
Authorization: Bearer <your API key>

{"chat_id": "19:xxxx@thread.v2", "text": "Deploying at 22:00 tonight"}

Finding the group id

Open the group in Teams → “⋯” next to the group name → Copy link. You get something like:

https://teams.microsoft.com/l/chat/19:xxxx@thread.v2/conversations?...

The 19:…@thread.v2 segment in the middle is the chat_id.

AlertBot has to be in that group first. In the group chat, click “⋯ → Apps”, search for AlertBot and add it — once is enough. Until then calls return 403/404, and the response includes a hint saying exactly this.

Channels (@thread.tacv2) aren't supported yet — only group chats (@thread.v2). Ask the platform owner if you need channel posts.

A group message interrupts a whole room. You own the call on what you send and how often. Every group message is audited, and the log can be queried by group: “who sent what into this chat”.

Send a card with a template

Rather than assembling Adaptive Card JSON yourself, pass a template_id plus params and the server renders it. Works for both DMs and group chats.

{"to": "someone@lofty.com",
 "template_id": "release-notice",
 "params": {"service": "payment-api", "version": "v2.3.1",
            "env": "prod", "url": "https://ci.example.com/build/1234"}}
template_idUseRequired paramsOptional params
release-noticeRelease / deploy noticeservice, versionenv, notes, url
alertAlerttitle, messageseverity, source, url
approval-requestApproval requesttitle, requesterdetails, url

Optional params you leave out are stripped from the card, so you don't get empty rows or dead buttons. You can also pass your own card (full Adaptive Card JSON) instead — supply exactly one of text, card, or template_id.

Template labels are currently Chinese. What language your notifications are in is the calling app's decision — if you need English cards, build the card JSON yourself, or ask the platform owner to add English templates.

Error codes

StatusMeaningWhat to do
200Delivered
400Bad parameters / unknown recipient / malformed group id / bot not in the groupRead error and detail.hint, fix and retry
401Key invalid or revokedCheck the key's status in the portal, or rotate it
502Upstream failure (Teams / Graph / Bot Framework)Retry later; if it keeps failing, send the requestId to the platform owner
500Channel-internal errorSend the requestId to the platform owner

Failures always come back as {"ok": false, "error": ..., "detail": ..., "requestId": ...}.

Error messages follow your Accept-Language header. Force one language with ?lang=en / ?lang=zh, or an X-Lang header.

Rules and limits