Agent Workflow
This guide walks through the canonical workflow for an AI agent automating Google review management on behalf of a business owner. Each step shows both the CLI command and the equivalent raw HTTP request.
Human setup required once. Google Business Profile OAuth requires a browser. Before an agent can operate, a human must: (1) create a Review Rover account, (2) connect Google Business Profile via Settings → Integrations, and (3) generate an API token at Settings → API Tokens and hand it to the agent.
Step 1 — Find or create a contact
Before enrolling a customer, check if they already exist using an email lookup. If they don't exist, create them. This prevents duplicate contacts.
Query parameters
- Name
email- Type
- string
- Description
Filter contacts by exact email address. Returns an empty list if no match is found.
Find by email
curl -G https://api.reviewrover.co/api/v1/contacts \
-H "Authorization: Bearer {token}" \
--data-urlencode "[email protected]"
Response
{
"has_more": false,
"data": [
{
"id": "cont_KYdl3lftgZXGRbxqoj",
"email": "[email protected]",
"first_name": "John",
"last_name": "Smith",
"phone": "555-1234",
"created_at": "2025-03-01T10:00:00Z",
"updated_at": "2025-03-01T10:00:00Z"
}
]
}
If the contact doesn't exist, create them with POST /v1/contacts.
Required attributes
- Name
email- Type
- string
- Description
The contact's email address.
Optional attributes
- Name
first_name- Type
- string
- Description
Contact's first name.
- Name
last_name- Type
- string
- Description
Contact's last name.
- Name
phone- Type
- string
- Description
Contact's phone number (used for SMS campaigns).
Create contact
curl https://api.reviewrover.co/api/v1/contacts \
-H "Authorization: Bearer {token}" \
-H "Content-Type: application/json" \
-d '{"email":"[email protected]","first_name":"John","last_name":"Smith","phone":"555-1234"}'
Response
{
"id": "cont_KYdl3lftgZXGRbxqoj",
"email": "[email protected]",
"first_name": "John",
"last_name": "Smith",
"phone": "555-1234",
"created_at": "2025-03-01T10:00:00Z",
"updated_at": "2025-03-01T10:00:00Z"
}
Step 2 — Pick a campaign
List available campaigns to find the right one for this contact. Campaigns define the message sequence (email/SMS) and the minimum star rating threshold.
List campaigns
curl https://api.reviewrover.co/api/v1/campaigns \
-H "Authorization: Bearer {token}"
Response
{
"has_more": false,
"data": [
{
"id": "camp_AbCdEfGhIjKlMn",
"name": "Post-Service Review Request",
"active": true,
"minimum_star_rating": 4,
"created_at": "2025-01-15T08:00:00Z"
}
]
}
Step 3 — Enroll the contact
Enrolling a contact triggers the campaign's message sequence immediately. The enrollment tracks progress through the sequence and marks itself completed once the contact submits a review.
Required attributes
- Name
contact_id- Type
- string
- Description
The ID of the contact to enroll.
- Name
campaign_id- Type
- string
- Description
The ID of the campaign to enroll them in.
Enroll contact
curl https://api.reviewrover.co/api/v1/enrollments \
-H "Authorization: Bearer {token}" \
-H "Content-Type: application/json" \
-d '{"contact_id":"cont_KYdl3lftgZXGRbxqoj","campaign_id":"camp_AbCdEfGhIjKlMn"}'
Response
{
"id": "enr_XxYyZz123456",
"contact_id": "cont_KYdl3lftgZXGRbxqoj",
"campaign_id": "camp_AbCdEfGhIjKlMn",
"completed": false,
"created_at": "2025-03-17T12:00:00Z"
}
Step 4 — Monitor the review queue
Poll this endpoint to check for new reviews that need a reply. It returns a structured summary optimized for agent use, including a per-location breakdown.
To avoid polling, register a webhook for the review.created event (see Step 6).
Unreplied reviews
curl https://api.reviewrover.co/api/v1/metrics/unreplied_reviews \
-H "Authorization: Bearer {token}"
Response
{
"count": 3,
"reviews": [
{
"id": "rev_Aa1Bb2Cc3Dd4Ee",
"rating": 5,
"author": "Jane D.",
"snippet": "Great service, highly recommend!",
"received_at": "2025-03-16T09:30:00Z"
}
],
"locations": [
{ "name": "Austin", "count": 2 },
{ "name": "Dallas", "count": 1 }
]
}
Step 5 — Draft and post a reply
Generate an AI-drafted reply first, then review and post it. The generate endpoint returns a suggested reply without saving it. The POST /reply endpoint saves and (if configured) posts it to Google.
Generate draft
curl -X POST \
https://api.reviewrover.co/api/v1/reviews/rev_Aa1Bb2Cc3Dd4Ee/reply/generate \
-H "Authorization: Bearer {token}"
Draft response
{
"draft": "Thank you so much for the kind words, Jane! We're thrilled to hear you had a great experience and we look forward to serving you again."
}
Once the draft looks good, save it as the official reply.
Required attributes
- Name
body- Type
- string
- Description
The reply text to post.
Post reply
curl -X POST \
https://api.reviewrover.co/api/v1/reviews/rev_Aa1Bb2Cc3Dd4Ee/reply \
-H "Authorization: Bearer {token}" \
-H "Content-Type: application/json" \
-d '{"body":"Thank you so much for the kind words, Jane!"}'
Response
{
"id": "rpl_MnOpQrSt123",
"review_id": "rev_Aa1Bb2Cc3Dd4Ee",
"body": "Thank you so much for the kind words, Jane!",
"created_at": "2025-03-17T13:00:00Z"
}
Step 6 — Register a webhook (optional)
Instead of polling for new reviews, register a webhook URL. Review Rover will POST to your URL whenever a review.created or enrollment.completed event fires.
All webhook payloads include an X-ReviewRover-Signature: sha256=<hmac> header for verification.
Required attributes
- Name
url- Type
- string
- Description
The HTTPS URL to deliver events to.
- Name
event_types- Type
- array
- Description
Events to subscribe to. Supported:
review.created,enrollment.completed.
Register webhook
curl https://api.reviewrover.co/api/v1/webhook_subscriptions \
-H "Authorization: Bearer {token}" \
-H "Content-Type: application/json" \
-d '{"url":"https://myagent.com/hook","event_types":["review.created"]}'
Response
{
"id": "whs_Uv1Wx2Yz3Ab4",
"url": "https://myagent.com/hook",
"event_types": ["review.created"],
"active": true,
"created_at": "2025-03-17T14:00:00Z"
}
Verify signature
When your endpoint receives a webhook, verify it came from Review Rover:
Verify webhook signature
const crypto = require('crypto')
function verifySignature(payload, signature, secret) {
const expected = crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex')
return `sha256=${expected}` === signature
}
// In your handler:
const sig = req.headers['x-reviewrover-signature']
if (!verifySignature(req.rawBody, sig, process.env.WEBHOOK_SECRET)) {
return res.status(401).send('Invalid signature')
}
Review velocity report
Use this endpoint to report review activity back to the business owner. Returns rolling counts and average ratings for the last 7 and 30 days.
Review velocity
curl https://api.reviewrover.co/api/v1/metrics/review_velocity \
-H "Authorization: Bearer {token}"
Response
{
"last_7_days": {
"count": 8,
"avg_rating": 4.6
},
"last_30_days": {
"count": 34,
"avg_rating": 4.4
}
}
