Prisma Reviews / Guides / Reviews to Intercom

Send customer reviews to Intercom as tickets

Teams that run support in Intercom want negative reviews in the same inbox, with an owner and a state, not in a separate dashboard nobody opens. Intercom has no reviews integration, but its Tickets API fits the job: one ticket per review below 4 stars, of a ticket type you create for reviews, with the rating, text and a link to answer. A Prisma webhook (one event per new review on 84 platforms) feeds it. About 40 lines of Python.

Shell
pip install flask requests

You need a Prisma API key and webhook secret, and an Intercom access token from a private app (Developer Hub → your app → Authentication) with permission to read and write tickets and contacts.

1. Set up Intercom once

  1. Ticket type: Settings → Tickets → Ticket types → New, type Back-office (internal, no customer emails), name it “Public review”. Note its id (GET https://api.intercom.io/ticket_types lists them).
  2. A contact to attach the tickets to: the reviewer isn’t an Intercom user, so create one lead for all of them:
cURL
curl -X POST https://api.intercom.io/contacts -H "Authorization: Bearer $INTERCOM_TOKEN" \
  -H "Intercom-Version: 2.11" -H "Content-Type: application/json" -d '{"role": "lead", "name": "Public reviews"}'

Keep the returned id.

2. Receive the review and create the ticket

Python
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']}"}
IC = {"Authorization": f"Bearer {os.environ['INTERCOM_TOKEN']}", "Intercom-Version": "2.11", "Content-Type": "application/json"}
TICKET_TYPE = os.environ["INTERCOM_TICKET_TYPE_ID"]
CONTACT = os.environ["INTERCOM_REVIEWS_CONTACT_ID"]
SEEN = set()   # use your database in production

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

@app.post("/webhooks/prisma")
def prisma_webhook():
    if not verify(request.get_data(), request.headers.get("Prisma-Signature", "")):
        abort(400)
    e = request.get_json()
    rid = e["data"]["id"]
    if e["type"] != "review.created" or rid in SEEN:
        return {"ok": True}
    r = requests.get(f"{PRISMA}/reviews/{rid}", headers=PH, timeout=30).json()
    if (r.get("rating") or 5) >= 4:
        return {"ok": True}
    title = f"{r['rating']}★ {r['platform']} review: {(r.get('title') or r.get('text') or '')[:60]}"
    desc = (f"By {r.get('author') or 'a customer'} on {r['created_at'][:10]} (location {r['location_id']}).\n\n"
            f"{r.get('title') or ''}\n{r.get('text') or ''}\n\nAnswer on the platform: {r.get('url') or '-'}\nPrisma review id: {r['id']}")
    body = {"ticket_type_id": TICKET_TYPE, "contacts": [{"id": CONTACT}],
            "ticket_attributes": {"_default_title_": title, "_default_description_": desc}}
    requests.post("https://api.intercom.io/tickets", headers=IC, json=body, timeout=30).raise_for_status()
    SEEN.add(rid)
    return {"ok": True}

_default_title_ and _default_description_ are the two attributes every ticket type has; add your own (Rating, Platform) to the ticket type and send them in ticket_attributes to filter and report in Intercom. Keep the Prisma review id in the description or a custom attribute so a redelivered webhook doesn’t create a second ticket.

3. Register the Prisma webhook

cURL
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"]}'

Answering

The ticket carries the link to answer on the platform. To publish the answer from your own tooling instead, call POST /v1/reviews/{id}/reply with the text the agent approved, on the platforms that accept replies (GET /v1/platforms says which: reply: "api"). The two-way pattern, where closing the case publishes the answer, is built step by step in reviews to Zendesk; with Intercom the trigger is a webhook on the ticket state change from your Intercom app.

Variants

The same webhook, other tools: HubSpot · Notion · Airtable · Zendesk · Slack (approve replies) · Slack (alerts) · Microsoft Teams · Discord · Google Sheets.

FAQ

Does Intercom import Google or App Store reviews?

No. Reviews reach Intercom through its REST API, typically as tickets created by your integration when a reviews webhook fires. A dedicated ticket type for reviews keeps them separate from customer conversations.

Which Intercom object should a review become?

A ticket of a custom type (for example Back-office or Tracker) titled with the rating and platform. It gets an owner, a state and SLAs like any case, without emailing the reviewer, who isn’t an Intercom contact.

Who is the ticket’s contact if the reviewer isn’t in Intercom?

Create one lead named after the platform’s reviews (for example “Public reviews”) once and attach every review ticket to it, or match the reviewer to an existing contact when your own data allows it.

Negative reviews in the support inbox, with an owner.

Get a free API key

2 locations free. Test keys return sample reviews, so the first ticket appears today.

Next step: see the 84 review platforms Prisma supports, and compare plans on Prisma Reviews pricing.

Get your API key in a minute

Free Spark plan: 2 locations, no card. Test keys return sample data on all 84 platforms, so you can build before connecting a real one.