Ce guide est disponible en anglais.
How to Build Automated Review-Response Workflows
Build a review-response workflow that routes reviews by rating and sentiment, drafts replies, approves them, and pushes them back to the platform.
En bref
- Ce que ce guide permet
- Turn incoming reviews into a routed, approvable reply workflow that posts back to the source platform.
- API utilisées
- get
/api/v1/reviewsLister les avis - post
/api/v1/reviews/replyRépondre à un avis - post
/api/v1/reviews/notesAjouter une note à un avis - get
/api/v1/reviews/notesLister les notes d'un avis - get
/api/v1/reviews/analyticsObtenir les statistiques d'avis
- get
- Référence
- Reviews
- Prérequis
- An API key with write access
- Locations whose reviews are already syncing
- Cas d'usage typiques
- Auto-replying to five-star reviews and routing the rest
- Building an approval queue for owner replies
- Keeping response rate high across many locations
Automating review responses is mostly a routing problem. Every reply is public and posts under the business's name, so the automation you actually want is not "reply to everything". It is "handle the easy ones, and get the rest in front of a person fast". Fetch, classify, draft, approve, send: that is the loop, and the risk lives entirely in who gets to skip the approve step.
The loop
- Fetch
GET /api/v1/reviews?status=unrepliedPull what is waiting, newest first - ClassifyBy rating and sentiment: auto-handle, or route to a person
- DraftA template for the simple case, a note for the escalation
- ApproveA human okays anything negative or sensitive
- Send
POST /api/v1/reviews/replyPushed to the source platform
Fetch what is waiting
GET /api/v1/reviews with status=unreplied is the queue. Pull it newest first and let the filters do the
first cut: ratings and sentiment are exactly the signals your routing keys on. Each review carries rating,
sentiment, a topics array of themes, and respondable, which is false when the source will not accept a reply.
curl "https://ai.synup.com/api/v1/reviews?locationId=LOCATION_ID&clientId=CLIENT_ID&status=unreplied&sort=newest&limit=100" \
-H "Authorization: Bearer $SYNUP_API_KEY"Route before you reply
The rule that keeps a workflow safe is simple: the higher the risk, the more human it gets. A reasonable default:
| Review | Handling |
|---|---|
| 5 star, positive, no text or short thanks | Auto-reply from a rotated template |
| 4 star, positive | Auto-reply, or one-click approve |
| 3 star, or mixed sentiment | Draft, route to a person |
| 1 to 2 star, or negative sentiment | Draft, require approval, notify the location |
respondable: false | Do not queue a reply at all |
The point is not these exact thresholds. It is that a rating and a sentiment are enough to split "send now" from "a person needs to see this", and the API hands you both on every review.
Draft, approve, then send
POST /api/v1/reviews/reply is the send. It posts the reply under the business's name and pushes it to the
platform, returning whether the push happened now, is queued, or failed with a retryable flag.
curl -X POST https://ai.synup.com/api/v1/reviews/reply \
-H "Authorization: Bearer $SYNUP_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "reviewId": "REVIEW_ID", "text": "Thanks so much for the kind words. We will pass this on to the team." }'const API = "https://ai.synup.com/api/v1";
const headers = {
Authorization: `Bearer ${process.env.SYNUP_API_KEY}`,
"Content-Type": "application/json",
};
const templates = {
five: ["Thank you for the kind words.", "We really appreciate you taking the time."],
};
function route(review) {
if (!review.respondable) return { action: "skip" };
if (review.rating >= 5 && review.sentiment === "positive") return { action: "auto" };
if (review.rating <= 2 || review.sentiment === "negative") return { action: "approve" };
return { action: "draft" };
}
async function handle(review) {
const decision = route(review);
if (decision.action === "auto") {
const text = templates.five[Math.floor(Math.random() * templates.five.length)];
return reply(review.id, text);
}
// draft or approve: park it for a person instead of sending
return addNote(review.id, `Routed to ${decision.action}: ${review.rating} star, ${review.sentiment}`);
}
async function reply(reviewId, text) {
const res = await fetch(`${API}/reviews/reply`, { method: "POST", headers, body: JSON.stringify({ reviewId, text }) });
if (res.status === 422) return { status: "not_respondable" };
if (!res.ok) throw new Error(`${res.status}: ${(await res.json()).error}`);
return (await res.json()).data;
}
async function addNote(reviewId, body) {
const res = await fetch(`${API}/reviews/notes`, { method: "POST", headers, body: JSON.stringify({ reviewId, body }) });
if (!res.ok) throw new Error(`${res.status}: ${(await res.json()).error}`);
return (await res.json()).data;
}import os, random, requests
API = "https://ai.synup.com/api/v1"
HEADERS = {"Authorization": f"Bearer {os.environ['SYNUP_API_KEY']}", "Content-Type": "application/json"}
TEMPLATES = {"five": ["Thank you for the kind words.", "We really appreciate you taking the time."]}
def route(review):
if not review.get("respondable"):
return "skip"
if review["rating"] >= 5 and review["sentiment"] == "positive":
return "auto"
if review["rating"] <= 2 or review["sentiment"] == "negative":
return "approve"
return "draft"
def handle(review):
action = route(review)
if action == "auto":
return reply(review["id"], random.choice(TEMPLATES["five"]))
return add_note(review["id"], f"Routed to {action}: {review['rating']} star, {review['sentiment']}")
def reply(review_id, text):
r = requests.post(f"{API}/reviews/reply", headers=HEADERS, timeout=30,
json={"reviewId": review_id, "text": text})
if r.status_code == 422:
return {"status": "not_respondable"}
r.raise_for_status()
return r.json()["data"]
def add_note(review_id, body):
r = requests.post(f"{API}/reviews/notes", headers=HEADERS, timeout=30,
json={"reviewId": review_id, "body": body})
r.raise_for_status()
return r.json()["data"]The escalations that a person needs to see go into a note, not a reply. POST /api/v1/reviews/notes attaches
team-only text (GET /api/v1/reviews/notes reads it back) that never reaches the platform, which is where the
"who is handling this" conversation belongs.
Measure whether it is working
GET /api/v1/reviews/analytics gives the number that tells you the workflow is doing its job: response rate,
with a period-over-period trend, per location. Watch it climb as the automation takes the easy volume off your
team. If response rate is flat, the routing is sending too much to people.
Next
When this grows into a product with campaigns, screening and widgets, that is the reputation platform guide. To let a model write the drafts instead of templates, see build an AI agent that responds to reviews. The single reply call is the respond to a review recipe.