Skip to main content

Request Review Controller

Source: internal/api/v1/reviews/controllers/request-review.js
Service: requestReview service
Module: Reviews


Overview

The Request Review controller manages manual review request campaigns. It enables sending review requests to customers via email, SMS, or both, with customizable templates and platform-specific review links.

Key Capabilities

  • Send Review Requests to selected contacts via email/SMS
  • Get Review Links for all connected platforms
  • List Review Requests with filtering and pagination
  • Get Request Filters for UI dropdowns
  • Update Email Templates for review requests
  • Get Current Template configuration

MongoDB Collections

CollectionOperationsPurpose
review-requestsCREATE, READTrack sent review requests
review-request-templatesREAD, UPDATEEmail/SMS templates
contactsREADCustomer contact information
review-configREADPlatform review links

Service Methods

1. send()

Send review requests to selected contacts.

Endpoint: POST /reviews/request-review/send

Controller Logic:

const send = catchAsync(async (req, res, next) => {
const body = validate(requestReviewSchema.send.body, req.body);
const account_id = req.auth.account_id;
const user_id = req.auth.uid;
const { type, contact_ids } = body;
const { errors, contact_ids: cids } = await requestReview.processData(
account_id,
contact_ids,
type,
);
const message = await requestReview.send(cids, type, account_id, user_id);

res.json({
success: true,
message,
errors: errors,
});
});

Request:

{
"type": "both",
"contact_ids": ["contact_abc123", "contact_xyz789"]
}

Request Body:

  • type (string): Delivery method - "email", "sms", or "both"
  • contact_ids (array): Array of contact IDs to send requests to

Response:

{
"success": true,
"message": "Your notifications are being processed.",
"errors": [
"Email not found for the contact John Doe. This contact will be skipped.",
"Phone number not found for Jane Smith. This contact will be skipped."
]
}

Business Logic Flow:

graph TD
A[Receive Send Request] --> B[Validate Contact IDs]
B --> C[Remove Duplicates]
C --> D[Fetch Contacts from DB]
D --> E{Contacts Found?}
E -->|No| F[Throw 404 Not Found]
E -->|Yes| G[Validate Contact Data]
G --> H{type = email?}
H -->|Yes| I[Check Email Exists]
I --> J{Has Email?}
J -->|No| K[Add to Errors Array]
G --> L{type = sms?}
L -->|Yes| M[Check Phone Exists]
M --> N{Has Phone?}
N -->|No| O[Add to Errors Array]
J -->|Yes| P[Process Valid Contacts]
N -->|Yes| P
K --> P
O --> P
P --> Q[Get Review Links]
Q --> R[Get Account Info]
R --> S[Find Twilio Number]
S --> T{Has Twilio Number?}
T -->|No| U[Throw Error]
T -->|Yes| V[Create ReviewRequest Doc]
V --> W[Call Notification Service]
W --> X[Return Success Message]

Email Template Variables:

  • {{business_name}} - Account business name
  • {{review_links}} - All platform links
  • {{google_link}} - Google review link
  • {{facebook_link}} - Facebook review link
  • {{yelp_link}} - Yelp review link

SMS Template:

Thanks for choosing [Business Name]. Would you please leave us a review?

[domain]/[account_id]/review

Key Features:

  1. Batch Processing: Send to multiple contacts at once
  2. Validation: Checks for required fields (email/phone)
  3. Error Handling: Returns partial success with error list
  4. Duplicate Prevention: Removes duplicate contact IDs
  5. Notification Queue: Async processing via notification service

Retrieve review links for all connected platforms.

Endpoint: GET /reviews/request-review/links

Request:

GET / api / v1 / a / reviews / request - review / links;

Response:

{
"success": true,
"data": {
"google": {
"platform": "google",
"url": "https://search.google.com/local/writereview?placeid=ChIJ...",
"icon": "google-icon.png"
},
"facebook": {
"platform": "facebook",
"url": "https://www.facebook.com/pg/[page-id]/reviews",
"icon": "facebook-icon.png"
},
"yelp": {
"platform": "yelp",
"url": "https://www.yelp.com/writeareview/biz/[business-id]",
"icon": "yelp-icon.png"
}
}
}

Use Cases:

  • Display review links in email template
  • Show links on website widget
  • Generate QR codes for physical locations
  • Social media post links

3. getRequests()

List all review requests with filtering.

Endpoint: GET /reviews/request-review/requests

Request:

GET /api/v1/v1/reviews/request-review/requests?filter=sent&page=1&limit=25&search=john

Query Parameters:

  • filter (string): Status filter - "sent", "opened", "clicked", "completed"
  • page (number): Page number
  • limit (number): Items per page
  • search (string): Search contact name/email

Response:

{
"success": true,
"data": [
{
"_id": "req_abc123",
"account_id": "acc_123",
"user_id": "user_456",
"type": "both",
"source": "reputation",
"receivers": ["contact_abc"],
"request_count": 1,
"status": "sent",
"sent_at": "2024-12-08T10:00:00Z",
"opened_at": null,
"clicked_at": null,
"completed_at": null
}
],
"pagination": {
"page": 1,
"limit": 25,
"total": 150,
"pages": 6
}
}

Status Definitions:

  • sent: Request sent successfully
  • opened: Recipient opened email
  • clicked: Recipient clicked review link
  • completed: Review submitted on platform

4. getRequestsFilters()

Get available filter options for requests list.

Endpoint: GET /reviews/request-review/filters

Response:

{
"success": true,
"data": {
"statuses": [
{ "value": "sent", "label": "Sent", "count": 150 },
{ "value": "opened", "label": "Opened", "count": 120 },
{ "value": "clicked", "label": "Clicked", "count": 75 },
{ "value": "completed", "label": "Completed", "count": 45 }
],
"types": [
{ "value": "email", "label": "Email", "count": 80 },
{ "value": "sms", "label": "SMS", "count": 50 },
{ "value": "both", "label": "Both", "count": 20 }
],
"sources": [
{ "value": "reputation", "label": "Manual", "count": 100 },
{ "value": "automated", "label": "Automated", "count": 50 }
]
}
}

5. updateTemplate()

Update the review request email/SMS template.

Endpoint: PUT /reviews/request-review/template

Request:

{
"subject": "We'd love your feedback!",
"email_body": "<p>Dear {{contact_name}},</p><p>Thank you for choosing {{business_name}}!</p>",
"sms_body": "Thanks {{contact_name}}! Please review us: {{review_link}}",
"from_name": "Acme Corp Team",
"from_email": "reviews@acmecorp.com"
}

Response:

{
"success": true,
"data": {
"_id": "template_abc",
"account_id": "acc_123",
"subject": "We'd love your feedback!",
"updated_at": "2024-12-08T15:00:00Z"
}
}

6. getTemplate()

Retrieve current template configuration.

Endpoint: GET /reviews/request-review/template

Response:

{
"success": true,
"data": {
"_id": "template_abc",
"account_id": "acc_123",
"subject": "We'd love your feedback!",
"email_body": "<p>Dear {{contact_name}}...</p>",
"sms_body": "Thanks! Review us: {{review_link}}",
"from_name": "Acme Corp Team",
"from_email": "reviews@acmecorp.com",
"created_at": "2024-12-01T10:00:00Z",
"updated_at": "2024-12-08T15:00:00Z"
}
}

Edge Cases & Error Handling

1. No Valid Contact IDs:

throw badRequest('No valid contact id is provided.');

2. Contacts Not Found:

throw notFound('No contact found with the provided ids');

3. Missing Email for Email Type:

errors.push(`Email not found for the contact ${contact.name}. This contact will be skipped.`);

4. Missing Phone for SMS Type:

errors.push(
`Phone number not found for the contact ${contact.name}. This contact will be skipped.`,
);

5. No Twilio Number:

throw notFound('No active phone number on the account');

6. Notification Service Error:

throw internalError(resp.data.message);

Authorization

Authentication: Required (JWT Bearer token)

Multi-Tenant Pattern:

const account_id = req.auth.account_id;
const user_id = req.auth.uid;

// Contacts must belong to same account
await Contact.find({ parent_account: account_id, _id: { $in: contact_ids } });

Integration Points

Dependencies:

  • CRM Contacts: Fetch contact email/phone
  • Review Config: Get platform review links
  • Twilio Numbers: SMS sending capability
  • Notification Service: Async email/SMS delivery

Triggers:

  • Review Request Created: Fires notification jobs
  • Link Clicked: Tracks engagement
  • Review Submitted: Marks as completed

Important Notes

Delivery Methods

  1. Email Only (type: "email"):

    • Uses SendGrid/email service
    • Includes all platform links
    • HTML template support
    • Track opens and clicks
  2. SMS Only (type: "sms"):

    • Uses Twilio
    • Plain text format
    • Character limit (160)
    • Universal review page link
  3. Both (type: "both"):

    • Sends email + SMS
    • Double engagement chance
    • Higher response rate
    • More costly
// Universal review page (all platforms)
const reviewPageUrl = `${domain}/${account_id}/review`;

// Platform-specific links from config
const googleLink = reviewConfig.google.url;
const facebookLink = reviewConfig.facebook.url;

Rate Limiting

  • Max 100 contacts per request: Prevent spam
  • Cooldown Period: 7 days between requests to same contact
  • Daily Limit: 500 requests per account per day


Version: 1.0
Last Updated: December 2024
Status: ✅ Production Ready

💬

Documentation Assistant

Ask me anything about the docs

Hi! I'm your documentation assistant. Ask me anything about the docs!

I can help you with:
- Code examples
- Configuration details
- Troubleshooting
- Best practices

Try asking: How do I configure the API?
09:31 AM