Reviews
Read, reply to, and analyze reviews, competitors, widgets, and review sources.
get_reviews_rollup
Reviews Overview / command center — across ALL of the agency's locations by default, or scoped to ONE client's locations by passing clientId (the Reviews → Overview page's "All locations" view for that client). Returns: summary tiles (total reviews, avg rating, total unreplied, positive %, new-in-period + Δ vs the prior window, stale count), the best & worst location by health, a per-location rows[] table (name/city, review count, avg rating, sentiment split, response rate, health score + Δ, %≤2★, %5★, 1–5★ distribution, new-in-window + velocity Δ, last-review date + staleness, a per-bucket sparkline, top positive/negative theme), and a portfolio trend (per-location monthly review volume + avg rating over the trailing 12 months, sorted by health). Window defaults to the last 30 days; pass period (7 | 30 | 90) or an explicit from+to ISO range.
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "get_reviews_rollup",
"arguments": {}
}
}{
"jsonrpc": "2.0",
"id": 1,
"result": {
"content": [
{
"type": "text",
"text": "..."
}
]
}
}Response shape shown for illustration — the actual content depends on the tool and your data.
list_reviews
List a location's reviews across its marketplaces (Google, Yelp, TripAdvisor, …). Location-scoped — requires clientId AND locationId. Cursor-paginated with a total count. Filters: ratings (1–5), sentiment (positive/neutral/negative), sites (platforms), status (responded | unreplied), keyword, from/to (ISO dates), sort (newest | oldest | lowest | highest). Reviews removed from their source are always excluded. Each review includes rating, body, author, date, platform, sentiment, existing reply, and respondable (whether a reply can be pushed via the API).
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "list_reviews",
"arguments": {
"clientId": "string",
"locationId": "string"
}
}
}{
"jsonrpc": "2.0",
"id": 1,
"result": {
"content": [
{
"type": "text",
"text": "..."
}
]
}
}Response shape shown for illustration — the actual content depends on the tool and your data.
get_review_stats
Get a location's review stat cards: total reviews, sentiment split (positive/neutral/negative), overall average rating, response rate (% of reviews with an owner reply), and per-platform review counts + averages. Location-scoped — requires clientId AND locationId. Removed reviews and hidden sources are excluded (matches the UI).
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "get_review_stats",
"arguments": {
"clientId": "string",
"locationId": "string"
}
}
}{
"jsonrpc": "2.0",
"id": 1,
"result": {
"content": [
{
"type": "text",
"text": "..."
}
]
}
}Response shape shown for illustration — the actual content depends on the tool and your data.
get_review_analytics
Deep-dive Review Analytics for a location: KPI cards with Δ vs the prior window (kpiDays 7/30/90) + sparklines, reviews-over-time + sentiment-over-time + response-rate trends (trendMonths 3/6/12), 1–5★ distribution, per-platform counts/averages, day-of-week timing, benchmark vs the agency average, top themes, and a Sydekick summary. Location-scoped — requires clientId AND locationId. Use the optional `section` to fetch just one slice (kpis | over_time | distribution | by_platform | timing | benchmark | topics | response | summary); omit for everything.
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "get_review_analytics",
"arguments": {
"clientId": "string",
"locationId": "string"
}
}
}{
"jsonrpc": "2.0",
"id": 1,
"result": {
"content": [
{
"type": "text",
"text": "..."
}
]
}
}Response shape shown for illustration — the actual content depends on the tool and your data.
reply_to_review
Post (or update) the owner reply to a single review, keyed by reviewId (get it from list_reviews). Google and Facebook replies are pushed live to the publisher via the API (respondable reviews; Facebook posts as a Page comment on the recommendation's open_graph_story); replies on other platforms are saved but not pushed. Calling again with new text EDITS the reply (Google stores exactly one owner reply per review — the re-post overwrites it; Facebook edits the existing Page comment rather than posting a duplicate). A Google reply can enter a `pending` or `rejected` moderation state after posting; it reconciles on the next sync. Returns { pushed } — whether it reached the publisher.
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "reply_to_review",
"arguments": {
"reviewId": "string",
"text": "string"
}
}
}{
"jsonrpc": "2.0",
"id": 1,
"result": {
"content": [
{
"type": "text",
"text": "..."
}
]
}
}Response shape shown for illustration — the actual content depends on the tool and your data.
delete_review_reply
Delete the owner reply to a single review, keyed by reviewId (from list_reviews). For Google and Facebook the reply is removed live on the publisher (Facebook deletes the Page comment); deleting a reply that is already gone still succeeds (idempotent). Only reviews on platforms that support delete (Google and Facebook today) can be deleted. In OS this is an archive, not a row delete — the record is kept internally (marked archived) even though it's genuinely gone from the publisher's page. Returns { ok, pushed } — whether it reached the publisher.
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "delete_review_reply",
"arguments": {
"reviewId": "string"
}
}
}{
"jsonrpc": "2.0",
"id": 1,
"result": {
"content": [
{
"type": "text",
"text": "..."
}
]
}
}Response shape shown for illustration — the actual content depends on the tool and your data.
add_review_note
Add an internal staff note to a single review, keyed by reviewId (get it from list_reviews). Notes are agency-internal — never shown to the client. Tenant-scoped: a review outside the caller's agency is rejected. Empty or over-4000-char bodies are rejected. Returns the created note. @-mentions are not supported (mentions stay empty).
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "add_review_note",
"arguments": {
"reviewId": "string",
"body": "string"
}
}
}{
"jsonrpc": "2.0",
"id": 1,
"result": {
"content": [
{
"type": "text",
"text": "..."
}
]
}
}Response shape shown for illustration — the actual content depends on the tool and your data.
list_review_notes
List the internal staff notes on a single review, newest-first, keyed by reviewId. Agency-internal — never client-facing. Tenant-scoped: a review outside the caller's agency is rejected. Returns { notes: [{ id, body, authorUserId, authorName, createdAt }] }.
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "list_review_notes",
"arguments": {
"reviewId": "string"
}
}
}{
"jsonrpc": "2.0",
"id": 1,
"result": {
"content": [
{
"type": "text",
"text": "..."
}
]
}
}Response shape shown for illustration — the actual content depends on the tool and your data.
delete_review_note
Permanently delete an internal staff note from a review. Identify it by reviewId (from list_reviews) and noteId (from list_review_notes). Tenant-scoped: a review outside the caller's agency is rejected. A note that's already gone (wrong id, or already deleted) is not an error — check the returned `deleted` count rather than assuming.
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "delete_review_note",
"arguments": {
"reviewId": "string",
"noteId": "string"
}
}
}{
"jsonrpc": "2.0",
"id": 1,
"result": {
"content": [
{
"type": "text",
"text": "..."
}
]
}
}Response shape shown for illustration — the actual content depends on the tool and your data.
get_competitor_analytics
Benchmark a location's Google reviews against its competitors. Location-scoped — requires clientId AND locationId. Returns competitive insight (Sydekick narrative + recommendations), strengths-vs-gaps (themes rivals win / you lead), a scorecard (self + each competitor: avg rating, review count, net sentiment, distribution), and review velocity + your share-of-voice. Use the optional `section` (insight | strengths_gaps | scorecard | velocity) to fetch one slice; omit for all. Manage the tracked set with add_competitor / remove_competitor / refresh_competitor.
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "get_competitor_analytics",
"arguments": {
"clientId": "string",
"locationId": "string"
}
}
}{
"jsonrpc": "2.0",
"id": 1,
"result": {
"content": [
{
"type": "text",
"text": "..."
}
]
}
}Response shape shown for illustration — the actual content depends on the tool and your data.
list_competitors
List the competitors tracked for a location (name, place id, rating, review count, sentiment). Location-scoped — requires clientId AND locationId. Use get_competitor for one competitor's detail, or get_competitor_analytics for the full benchmark.
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "list_competitors",
"arguments": {
"clientId": "string",
"locationId": "string"
}
}
}{
"jsonrpc": "2.0",
"id": 1,
"result": {
"content": [
{
"type": "text",
"text": "..."
}
]
}
}Response shape shown for illustration — the actual content depends on the tool and your data.
get_competitor
Get one tracked competitor's profile for a location (rating, review count, sentiment, etc.). Location-scoped — requires clientId, locationId, and competitorId (from list_competitors).
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "get_competitor",
"arguments": {
"clientId": "string",
"locationId": "string",
"competitorId": "string"
}
}
}{
"jsonrpc": "2.0",
"id": 1,
"result": {
"content": [
{
"type": "text",
"text": "..."
}
]
}
}Response shape shown for illustration — the actual content depends on the tool and your data.
add_competitor
Track a new competitor for a location, by business name (matched to Google). Location-scoped — requires clientId, locationId, name. Returns the created competitor profile.
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "add_competitor",
"arguments": {
"clientId": "string",
"locationId": "string",
"name": "string"
}
}
}{
"jsonrpc": "2.0",
"id": 1,
"result": {
"content": [
{
"type": "text",
"text": "..."
}
]
}
}Response shape shown for illustration — the actual content depends on the tool and your data.
add_client_competitor
Track a new competitor at the CLIENT level (a roll-up competitor shown across every location for that client), by business name. Distinct from add_competitor, which tracks one for a single location. Returns the created competitor profile.
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "add_client_competitor",
"arguments": {
"clientId": "string",
"name": "string"
}
}
}{
"jsonrpc": "2.0",
"id": 1,
"result": {
"content": [
{
"type": "text",
"text": "..."
}
]
}
}Response shape shown for illustration — the actual content depends on the tool and your data.
refresh_client_competitors
Trigger competitor auto-discovery and a fresh review pull across an entire client (every one of its locations), rather than one already-tracked competitor. Runs in the background — discovery plus a deep review pull can take longer than a single request allows for a large client. Returns { ok, queued }; there is no synchronous result to check.
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "refresh_client_competitors",
"arguments": {
"clientId": "string"
}
}
}{
"jsonrpc": "2.0",
"id": 1,
"result": {
"content": [
{
"type": "text",
"text": "..."
}
]
}
}Response shape shown for illustration — the actual content depends on the tool and your data.
remove_competitor
Stop tracking a competitor, by competitorId (from list_competitors). Agency-scoped.
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "remove_competitor",
"arguments": {
"competitorId": "string"
}
}
}{
"jsonrpc": "2.0",
"id": 1,
"result": {
"content": [
{
"type": "text",
"text": "..."
}
]
}
}Response shape shown for illustration — the actual content depends on the tool and your data.
refresh_competitor
Re-scrape a single tracked competitor's Google reviews, by competitorId (from list_competitors). Returns { ok, note }.
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "refresh_competitor",
"arguments": {
"competitorId": "string"
}
}
}{
"jsonrpc": "2.0",
"id": 1,
"result": {
"content": [
{
"type": "text",
"text": "..."
}
]
}
}Response shape shown for illustration — the actual content depends on the tool and your data.
get_topic_trends
What customers talk about for a location: a topic leaderboard (mentions, avg rating, sentiment) plus rising / declining / emerging / faded movers and an Sydekick narrative, over a window of days. Location-scoped — requires clientId AND locationId. Optional windowDays (default 90) and section (topics | movers | narrative | all). This is also the source for the 'what customers talk about' chips.
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "get_topic_trends",
"arguments": {
"clientId": "string",
"locationId": "string"
}
}
}{
"jsonrpc": "2.0",
"id": 1,
"result": {
"content": [
{
"type": "text",
"text": "..."
}
]
}
}Response shape shown for illustration — the actual content depends on the tool and your data.
get_topic_series
Topic trends over time for a location — the per-topic monthly sentiment/mention series behind the Topic Trends heatmap. Location-scoped — requires clientId AND locationId. Optional months (default 12).
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "get_topic_series",
"arguments": {
"clientId": "string",
"locationId": "string"
}
}
}{
"jsonrpc": "2.0",
"id": 1,
"result": {
"content": [
{
"type": "text",
"text": "..."
}
]
}
}Response shape shown for illustration — the actual content depends on the tool and your data.
get_topic_reviews
List the reviews that mention a specific topic for a location (drill-down from get_topic_trends). Location-scoped — requires clientId, locationId, and topic. Optional month (YYYY-MM) narrows to a single month — pass it when the caller is drilling into ONE cell of the topics-by-month heatmap, or you get the topic's whole history newest-first instead of that cell's reviews. Optional limit (default 50).
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "get_topic_reviews",
"arguments": {
"clientId": "string",
"locationId": "string",
"topic": "string"
}
}
}{
"jsonrpc": "2.0",
"id": 1,
"result": {
"content": [
{
"type": "text",
"text": "..."
}
]
}
}Response shape shown for illustration — the actual content depends on the tool and your data.
list_review_widgets
List the review widgets configured for a location (embeddable review displays for the client's website). Location-scoped — requires clientId AND locationId.
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "list_review_widgets",
"arguments": {
"clientId": "string",
"locationId": "string"
}
}
}{
"jsonrpc": "2.0",
"id": 1,
"result": {
"content": [
{
"type": "text",
"text": "..."
}
]
}
}Response shape shown for illustration — the actual content depends on the tool and your data.
get_review_widget
Get a single review widget by id (its config + status). Agency-scoped.
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "get_review_widget",
"arguments": {
"widgetId": "string"
}
}
}{
"jsonrpc": "2.0",
"id": 1,
"result": {
"content": [
{
"type": "text",
"text": "..."
}
]
}
}Response shape shown for illustration — the actual content depends on the tool and your data.
count_widget_matches
Count how many of a location's reviews match a widget configuration — the live '{N} reviews match this configuration' preview. Location-scoped — requires clientId AND locationId. Optional minRating, sources, includeInternal, dateWindow (30d | 90d | 1y | all).
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "count_widget_matches",
"arguments": {
"clientId": "string",
"locationId": "string"
}
}
}{
"jsonrpc": "2.0",
"id": 1,
"result": {
"content": [
{
"type": "text",
"text": "..."
}
]
}
}Response shape shown for illustration — the actual content depends on the tool and your data.
create_review_widget
Create an embeddable review widget for a location. Location-scoped — requires clientId, locationId, name. Optional: minRating, sources, selectionMode (recent | highest | manual), dateWindow, count, includeInternal, layout (carousel | grid | wall), status (draft | published, default published). Use count_widget_matches first to preview how many reviews match.
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "create_review_widget",
"arguments": {
"clientId": "string",
"locationId": "string",
"name": "string"
}
}
}{
"jsonrpc": "2.0",
"id": 1,
"result": {
"content": [
{
"type": "text",
"text": "..."
}
]
}
}Response shape shown for illustration — the actual content depends on the tool and your data.
delete_review_widget
Delete a review widget by id. Agency-scoped.
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "delete_review_widget",
"arguments": {
"widgetId": "string"
}
}
}{
"jsonrpc": "2.0",
"id": 1,
"result": {
"content": [
{
"type": "text",
"text": "..."
}
]
}
}Response shape shown for illustration — the actual content depends on the tool and your data.
list_review_campaigns
List a location's review-acquisition campaigns (email/SMS review requests). Location-scoped — requires clientId AND locationId. Paginated.
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "list_review_campaigns",
"arguments": {
"clientId": "string",
"locationId": "string"
}
}
}{
"jsonrpc": "2.0",
"id": 1,
"result": {
"content": [
{
"type": "text",
"text": "..."
}
]
}
}Response shape shown for illustration — the actual content depends on the tool and your data.
get_invite_stats
Get review-invite acquisition stats for a location: total acquisitions, feedback received, customer-experience score, click-through rate. Location-scoped — requires clientId AND locationId.
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "get_invite_stats",
"arguments": {
"clientId": "string",
"locationId": "string"
}
}
}{
"jsonrpc": "2.0",
"id": 1,
"result": {
"content": [
{
"type": "text",
"text": "..."
}
]
}
}Response shape shown for illustration — the actual content depends on the tool and your data.
list_campaign_responses
List responses to a location's review-invite campaigns (who responded, feedback given). Location-scoped — requires clientId AND locationId. Paginated.
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "list_campaign_responses",
"arguments": {
"clientId": "string",
"locationId": "string"
}
}
}{
"jsonrpc": "2.0",
"id": 1,
"result": {
"content": [
{
"type": "text",
"text": "..."
}
]
}
}Response shape shown for illustration — the actual content depends on the tool and your data.
list_campaign_recipients
List recipients of a location's review-invite campaigns (contacts messaged + delivery/response status). Location-scoped — requires clientId AND locationId. Paginated.
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "list_campaign_recipients",
"arguments": {
"clientId": "string",
"locationId": "string"
}
}
}{
"jsonrpc": "2.0",
"id": 1,
"result": {
"content": [
{
"type": "text",
"text": "..."
}
]
}
}Response shape shown for illustration — the actual content depends on the tool and your data.
get_campaign
Get a single review-invite campaign by id (config, status, schedule). Agency-scoped.
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "get_campaign",
"arguments": {
"campaignId": "string"
}
}
}{
"jsonrpc": "2.0",
"id": 1,
"result": {
"content": [
{
"type": "text",
"text": "..."
}
]
}
}Response shape shown for illustration — the actual content depends on the tool and your data.
bulk_reply_reviews
Post replies to many reviews in one call. Pass `replies` as an explicit array of { reviewId, text }. Each is applied independently (Google and Facebook pushed live; others saved). Rate-limited per Google Business Profile (10 edits/min); throttled items come back with retryable:true so they can be re-attempted rather than treated as hard failures. Returns a per-review result array with ok/pushed/error/retryable, plus succeeded/failed counts.
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "bulk_reply_reviews",
"arguments": {
"replies": [
{}
]
}
}
}{
"jsonrpc": "2.0",
"id": 1,
"result": {
"content": [
{
"type": "text",
"text": "..."
}
]
}
}Response shape shown for illustration — the actual content depends on the tool and your data.
validate_review_source
Check whether a URL is a usable review source before adding it with add_review_source. Probes the page live (a few seconds), detecting its platform (Google/Yelp/Facebook/TripAdvisor/Trustpilot/BBB/Foursquare/Healthgrades/OpenTable/custom), whether it actually collects reviews, an estimated review count, and the business name found on the page. If you pass locationId, it also checks whether the page's business name matches that location's name and whether this URL is already added there; omit locationId to instead get a suggested location match by name. `ok` is true only when the source collects reviews AND isn't a duplicate.
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "validate_review_source",
"arguments": {
"url": "string"
}
}
}{
"jsonrpc": "2.0",
"id": 1,
"result": {
"content": [
{
"type": "text",
"text": "..."
}
]
}
}Response shape shown for illustration — the actual content depends on the tool and your data.
add_review_source
Add a custom review source (a specific review-page URL) to a location — e.g. a Yelp, TripAdvisor, Trustpilot, BBB, or other business-listing page whose reviews aren't already pulled in automatically (Google and Facebook are auto-pulled via the connected OAuth account and don't need this). Run validate_review_source on the URL first to confirm it collects reviews and isn't already added. Once added, its reviews are scraped immediately in the background and then re-checked on a recurring schedule. Fails if this exact URL is already added to this location.
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "add_review_source",
"arguments": {
"locationId": "string",
"url": "string"
}
}
}{
"jsonrpc": "2.0",
"id": 1,
"result": {
"content": [
{
"type": "text",
"text": "..."
}
]
}
}Response shape shown for illustration — the actual content depends on the tool and your data.
hide_review_source
Hide or unhide a review source from a location's review feed and analytics, without deleting its historical reviews. Pass an auto-detected platform slug (e.g. "google") with type "auto" to hide one of the automatically-pulled platforms, or a custom source's id (from validate_review_source's result, or the id returned by add_review_source) with type "custom".
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "hide_review_source",
"arguments": {
"locationId": "string",
"key": "string",
"type": "auto",
"hide": true
}
}
}{
"jsonrpc": "2.0",
"id": 1,
"result": {
"content": [
{
"type": "text",
"text": "..."
}
]
}
}Response shape shown for illustration — the actual content depends on the tool and your data.
remove_review_source
Permanently remove a custom review source from a location. This only removes the tracked source going forward — reviews already imported into the app from it are NOT deleted. Only custom sources (added via add_review_source) can be removed this way; the auto-pulled platforms (Google, Facebook) can only be hidden with hide_review_source, not removed. Identify the source by its id (from add_review_source's result, or a "custom:<id>" key seen elsewhere).
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "remove_review_source",
"arguments": {
"sourceId": "string"
}
}
}{
"jsonrpc": "2.0",
"id": 1,
"result": {
"content": [
{
"type": "text",
"text": "..."
}
]
}
}Response shape shown for illustration — the actual content depends on the tool and your data.