Prisma Reviews / Guides / Review alerts in Microsoft Teams
New review alerts in Microsoft Teams
Teams is where many multi-location companies and agencies already coordinate, and a review channel there works the same as in Slack: every new review lands as a card with the stars, the text, who wrote it and a button to answer. Teams’ old incoming-webhook connectors are being retired, so this guide uses the supported route, a Workflows webhook that posts an Adaptive Card. A Prisma webhook (one event per new review on 84 platforms) feeds it; the glue is about 30 lines of Python.
pip install flask requests1. Create the Teams webhook URL
In the Teams channel: ⋯ → Workflows → “Post to a channel when a webhook request is received”, pick the team and channel, and copy the URL it gives you (it starts with https://prod-…logic.azure.com or https://…powerplatform.com). Anyone with the URL can post to the channel, so keep it in an environment variable.
2. Receive the review and post the card
import hashlib, hmac, os, time, requests
from flask import Flask, request, abort
app = Flask(__name__)
PRISMA = "https://api.prismareviews.com/v1"
PH = {"Authorization": f"Bearer {os.environ['PRISMA_API_KEY']}"}
TEAMS_URL = os.environ["TEAMS_WORKFLOW_URL"]
def verify(raw: bytes, header: str) -> bool:
parts = dict(p.split("=", 1) for p in header.split(","))
expected = hmac.new(os.environ["PRISMA_WEBHOOK_SECRET"].encode(), f"{parts['t']}.".encode() + raw, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, parts["v1"]) and abs(time.time() - int(parts["t"])) < 300
def card(r: dict) -> dict:
stars = "★" * (r["rating"] or 0) + "☆" * (5 - (r["rating"] or 0))
return {"type": "message", "attachments": [{"contentType": "application/vnd.microsoft.card.adaptive", "content": {
"type": "AdaptiveCard", "$schema": "http://adaptivecards.io/schemas/adaptive-card.json", "version": "1.4",
"body": [
{"type": "TextBlock", "text": f"{stars} {r['platform']}", "weight": "Bolder", "size": "Medium",
"color": "Attention" if (r["rating"] or 5) <= 2 else "Default"},
{"type": "TextBlock", "text": r.get("title") or "", "weight": "Bolder", "wrap": True},
{"type": "TextBlock", "text": (r.get("text") or "")[:1500], "wrap": True},
{"type": "FactSet", "facts": [{"title": "By", "value": r.get("author") or "a customer"},
{"title": "Date", "value": r["created_at"][:10]},
{"title": "Location", "value": r["location_id"]}]}],
"actions": [{"type": "Action.OpenUrl", "title": "Answer on the platform", "url": r.get("url") or "https://prismareviews.com"}]}}]}
@app.post("/webhooks/prisma")
def prisma_webhook():
if not verify(request.get_data(), request.headers.get("Prisma-Signature", "")):
abort(400)
e = request.get_json()
if e["type"] == "review.created":
r = requests.get(f"{PRISMA}/reviews/{e['data']['id']}", headers=PH, timeout=30).json()
requests.post(TEAMS_URL, json=card(r), timeout=30).raise_for_status()
return {"ok": True}The Workflows URL answers 202 Accepted; the card appears in the channel a few seconds later. Adaptive Card 1.4 is what Teams renders reliably; keep the text under a couple of thousand characters.
3. Register the Prisma webhook
curl -X POST https://api.prismareviews.com/v1/webhooks \
-H "Authorization: Bearer $PRISMA_API_KEY" -H "Content-Type: application/json" \
-d '{"url": "https://yourapp.example.com/webhooks/prisma", "events": ["review.created"]}'Variants
- Bad reviews to the managers’ channel: create a second Workflows URL in a private channel and post there when
r["rating"] <= 2. - One channel per location: keep
location_id → workflow URLin a table; agencies often map one Teams channel per client. - No code: n8n’s Prisma Reviews trigger (verified node, n8n setup) → HTTP Request node posting the same card JSON to the Workflows URL. Power Automate itself can also be the receiver: its “When a HTTP request is received” trigger can take Prisma’s webhook directly, then call
GET /v1/reviews/{id}with an HTTP action.
The same webhook, other tools: HubSpot · Notion · Airtable · Zendesk · Intercom · Slack (approve replies) · Slack (alerts) · Discord · Google Sheets.
FAQ
Should I use an Office 365 connector incoming webhook for Teams?
No. Microsoft is retiring Office 365 connectors in Teams and points to Workflows instead: the “Post to a channel when a webhook request is received” template gives you an HTTPS URL that accepts an Adaptive Card and posts it to the channel.
What payload does the Teams Workflows webhook expect?
A message with an attachments array whose item has contentType application/vnd.microsoft.card.adaptive and the Adaptive Card JSON in content. Plain text alone isn’t rendered by the default template.
Can people answer the review from Teams?
The card’s Answer button opens the review on the platform. Publishing a reply from inside Teams needs a Teams bot; the simpler route is the Slack-style approval flow or your own tool calling POST /v1/reviews/{id}/reply.
Every new review, in the Teams channel that owns it.
2 locations free. Test keys return sample reviews, so the card posts today.