Prisma Reviews / Guides / Reviews to HubSpot

Send customer reviews to HubSpot automatically: notes on the company record

HubSpot has no integration that brings Google, App Store, Trustpilot or Yelp reviews into the CRM, and its Feedback Submissions object is read-only through the API. What works is to create a note on the company (or contact) record for each new review, with the rating, the text and the link to answer. This guide does it in about 40 lines of Python: a Prisma webhook tells you a review arrived, you fetch it, and you create the note with HubSpot’s CRM API. The same flow in n8n, without code, is at the end. For a multi-location business the company record is the location’s customer; for an agency it’s each client.

Shell
pip install flask requests

You need a Prisma API key, a Prisma webhook secret (shown once when you create the webhook), and a HubSpot private app token (Settings → Integrations → Private apps) with the crm.objects.notes.write and crm.objects.companies.read scopes.

1. Map locations to HubSpot companies

Keep a small table from Prisma location_id to HubSpot company id. The simplest place is a dict; a real integration stores it with the connection.

Python
COMPANY_FOR_LOCATION = {
    "loc_01KJ8…": "1234567890",   # Prisma location → HubSpot company id
}

2. Receive the webhook, verify it, fetch the review

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']}"}
SECRET = os.environ["PRISMA_WEBHOOK_SECRET"]

def verify(raw: bytes, header: str) -> bool:
    parts = dict(p.split("=", 1) for p in header.split(","))
    expected = hmac.new(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)
    event = request.get_json()
    if event["type"] != "review.created":
        return {"ok": True}
    review = requests.get(f"{PRISMA}/reviews/{event['data']['id']}", headers=PH, timeout=30).json()
    company = COMPANY_FOR_LOCATION.get(review["location_id"])
    if company:
        create_note(company, review)
    return {"ok": True}

The review.created payload carries only ids (id, location_id, platform), so the fetch is where the text comes from. The signature is t=<unix>,v1=<HMAC-SHA256 of "t.body">; the full check is in the webhooks reference.

3. Create the note on the company

Python
HS = {"Authorization": f"Bearer {os.environ['HUBSPOT_TOKEN']}", "Content-Type": "application/json"}

def create_note(company_id: str, r: dict):
    stars = "★" * (r["rating"] or 0) + "☆" * (5 - (r["rating"] or 0))
    body = (f"<p><strong>{r['platform']} review, {stars}</strong> by {r.get('author') or 'a customer'}</p>"
            f"<p>{(r.get('title') or '')}</p><p>{(r.get('text') or '')}</p>"
            f"<p><a href=\"{r.get('url') or ''}\">Answer on the platform</a></p>")
    payload = {
        "properties": {"hs_timestamp": r["created_at"], "hs_note_body": body},
        "associations": [{"to": {"id": company_id}, "types": [{"associationCategory": "HUBSPOT_DEFINED", "associationTypeId": 190}]}],
    }
    res = requests.post("https://api.hubapi.com/crm/v3/objects/notes", headers=HS, json=payload, timeout=30)
    res.raise_for_status()
    return res.json()["id"]

associationTypeId 190 is HubSpot’s note-to-company association; use 202 for note-to-contact. hs_timestamp takes the review’s date so the note sits at the right point of the timeline. HubSpot’s private-app limit is 100 requests per 10 seconds, far above what reviews produce.

4. Register the 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"]}'

The response includes the secret for PRISMA_WEBHOOK_SECRET. Deliveries retry with backoff (30 s doubling to 1 h) when your endpoint doesn’t answer 2xx, with the same event id, so an occasional restart loses nothing.

5. The same with n8n, no code

Prisma Reviews trigger (new review) → HubSpot node, resource Engagement, type Note, with the company association and the rating, text and URL in the body. The Prisma node is verified on n8n Cloud (n8n setup); the mapping from location to company is a Code node or a Google Sheet lookup.

Variants

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

FAQ

Does HubSpot have a native Google reviews integration?

No. HubSpot’s own feedback surveys are its Feedback Submissions object, which the API only reads. External reviews reach HubSpot through the CRM API: as notes, custom-object records or timeline events created by your integration.

Which HubSpot object should a review become?

A note associated to the company (or contact) is the simplest and works on every HubSpot tier: it shows in the record’s timeline with the rating, text and link. A custom object named Reviews is better for reporting but needs Enterprise.

How does my server know a new review arrived?

Register a webhook with POST /v1/webhooks for review.created. Prisma sends the review’s id, location and platform, signed with Prisma-Signature; your endpoint fetches the full review with GET /v1/reviews/{id} and creates the HubSpot note.

Every review, in the CRM, the minute it lands.

Get a free API key

2 locations free. Test keys return sample reviews, so the webhook fires 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.