Skip to content

Profile Comments API Reference

The Profile Comments API exposes feedback that is scoped to a profile and location, rather than to an individual post. It surfaces Google Business Profile reviews and Facebook Page recommendations — both live on a location or Page, not on a post, so they cannot be expressed through the post-level Comments API.

All write operations are processed asynchronously.

MethodEndpointDescription
GET/api/profiles/:profile_id/commentsList top-level comments + their replies
GET/api/profiles/:profile_id/comments/:idGet a single comment
POST/api/profiles/:profile_id/commentsCreate a reply to an existing comment
DELETE/api/profiles/:profile_id/comments/:idDelete your reply (the original review stays)

Endpoints that accept a comment :id in the path, and the parent_id field on POST, accept either:

  • Postproxy ID: the comment’s hashid (e.g. abc123xyz)
  • External ID: the platform’s native ID — Google’s resource path (e.g. accounts/1234/locations/5678/reviews/AbFvOq) or Facebook’s recommendation story ID (e.g. 122219817518532572)

With a sandbox key, review replies and deletes are answered by sandbox plugins, and profile_comment.created reaches your sandbox webhook endpoints — without touching the engagement quota. Incoming Google Business reviews and Facebook recommendations are fabricated from the Sandbox page in the dashboard.


ActionGoogle BusinessFacebook
ListYes (reviews on the location)Yes (recommendations on the Page)
ReplyYes (one reply per review)Yes (a comment on the recommendation; several allowed)
DeleteYes (removes your reply; the review stays)Yes (removes your comment; the recommendation stays)

Top-level comments cannot be authored — reviews come from end users. POST requests must supply a parent_id pointing at the review you are replying to.

  • platform_data.review_reply_url on a review is Google’s “reply to this review” link for the business owner.
  • Reviews removed on Google (by the reviewer or by Google moderation) and owner replies deleted outside Postproxy are marked status: "deleted" on the next sync. Deleted rows drop out of list responses but remain fetchable by id, and a profile_comment.deleted webhook fires for each one.
  • Replies carry platform_data.reply_state (PENDING, APPROVED, or REJECTED) — Google moderates owner replies. When the state is REJECTED, platform_data.policy_violation names the reason (e.g. FAKE_ENGAGEMENT, OFF_TOPIC, PERSONAL_INFO). Both come back on the POST reply response once published and are refreshed on every sync.
  • platform_data.recommendation_type is "positive" or "negative". platform_data.star_rating is only present on legacy reviews left before Facebook replaced stars with recommendations (2018).
  • Meta does not expose who left a recommendation — author_username and author_avatar_url are always null on Facebook rows.
  • placement_id is the Page ID.

Google rows point to the location’s reviews page on Google (https://search.google.com/local/reviews?placeid=...); Facebook rows point to the Page’s reviews tab (https://www.facebook.com/<page_id>/reviews). The link is shared by all reviews and replies on that location / Page — neither platform exposes per-review URLs. permalink is null for Google when the location’s placeId is unavailable.

Google Business reviews are pulled from Google hourly for every active, eligible google_business profile.

Facebook recommendations are backfilled once when the profile connects, then kept current in real time — new recommendations, edits, removals, and comments on them land within seconds.


GET /api/profiles/:profile_id/comments

Retrieves a paginated list of top-level comments for a profile. Each top-level comment includes a replies array containing all nested replies sorted by created_at ascending.

ParameterTypeRequiredDescription
profile_idstringYesProfile ID (hashid)
ParameterTypeRequiredDefaultDescription
placement_idstringNo-Filter to comments on a single location / Page (the accounts/X/locations/Y path or Page ID returned by List Placements)
pageintegerNo1Page number (1-based). Passing 0 returns page 1
per_pageintegerNo20Number of top-level comments per page

Results are sorted by posted_at descending (newest first). Records without a posted_at are returned last.

Google Business reviews can be star-only (no text). For these, body is null while platform_data.star_rating is still populated — don’t skip records on a null body.

Terminal window
curl -X GET "https://api.postproxy.dev/api/profiles/PROFILE_ID/comments?page=1&per_page=20" \
-H "Authorization: Bearer YOUR_API_KEY"

Response:

{
"total": 2,
"page": 1,
"per_page": 20,
"data": [
{
"id": "abc123",
"external_id": "accounts/1234/locations/5678/reviews/AbFvOq",
"parent_external_id": null,
"placement_id": "accounts/1234/locations/5678",
"body": "Great coffee, friendly staff!",
"status": "synced",
"author_username": "Jane D.",
"author_avatar_url": "https://lh3.googleusercontent.com/...",
"platform_data": { "star_rating": 5, "update_time": "2026-05-10T12:00:00Z", "review_reply_url": "https://business.google.com/..." },
"permalink": "https://search.google.com/local/reviews?placeid=ChIJxyz",
"posted_at": "2026-05-10T11:55:00Z",
"created_at": "2026-05-13T06:00:01Z",
"replies": [
{
"id": "def456",
"external_id": "accounts/1234/locations/5678/reviews/AbFvOq/reply",
"parent_external_id": "accounts/1234/locations/5678/reviews/AbFvOq",
"placement_id": "accounts/1234/locations/5678",
"body": "Thanks Jane — see you again soon!",
"status": "published",
"author_username": null,
"author_avatar_url": null,
"platform_data": { "reply_state": "APPROVED" },
"permalink": "https://search.google.com/local/reviews?placeid=ChIJxyz",
"posted_at": "2026-05-12T15:00:00Z",
"created_at": "2026-05-12T15:00:01Z"
}
]
}
]
}
FieldTypeDescription
totalintegerTotal number of top-level comments
pageintegerCurrent page number
per_pageintegerItems per page
dataarrayArray of top-level comment objects, each with a replies array

Pagination applies to top-level comments only. All replies are flattened into the replies array of their root top-level comment, sorted by created_at ascending. Each reply retains its parent_external_id so the client can reconstruct the tree if needed.


GET /api/profiles/:profile_id/comments/:id

Retrieves a single comment with its direct replies.

ParameterTypeRequiredDescription
profile_idstringYesProfile ID
idstringYesComment ID or external ID
Terminal window
curl -X GET "https://api.postproxy.dev/api/profiles/PROFILE_ID/comments/COMMENT_ID" \
-H "Authorization: Bearer YOUR_API_KEY"

Response:

{
"id": "abc123",
"external_id": "accounts/1234/locations/5678/reviews/AbFvOq",
"parent_external_id": null,
"placement_id": "accounts/1234/locations/5678",
"body": "Great coffee, friendly staff!",
"status": "synced",
"author_username": "Jane D.",
"author_avatar_url": "https://lh3.googleusercontent.com/...",
"platform_data": { "star_rating": 5, "update_time": "2026-05-10T12:00:00Z", "review_reply_url": "https://business.google.com/..." },
"permalink": "https://search.google.com/local/reviews?placeid=ChIJxyz",
"posted_at": "2026-05-10T11:55:00Z",
"created_at": "2026-05-13T06:00:01Z",
"replies": [
{
"id": "def456",
"external_id": "accounts/1234/locations/5678/reviews/AbFvOq/reply",
"parent_external_id": "accounts/1234/locations/5678/reviews/AbFvOq",
"placement_id": "accounts/1234/locations/5678",
"body": "Thanks Jane — see you again soon!",
"status": "published",
"author_username": null,
"author_avatar_url": null,
"platform_data": { "reply_state": "APPROVED" },
"permalink": "https://search.google.com/local/reviews?placeid=ChIJxyz",
"posted_at": "2026-05-12T15:00:00Z",
"created_at": "2026-05-12T15:00:01Z"
}
]
}

POST /api/profiles/:profile_id/comments

Creates a reply to an existing review. The reply is stored immediately with status: "pending" and external_id: null; it is then published to the platform and the status updates to published once it lands (or failed / failed_waiting_for_retry with error and error_details populated).

On Google Business a review can carry one reply; on Facebook a recommendation is replied to with a comment, and several are allowed.

Top-level comments cannot be created — the request returns 422 if parent_id is missing.

ParameterTypeRequiredDescription
parent_idstringYesPostproxy ID or external ID of the review being replied to
bodystringYesReply body. (The legacy text parameter is still accepted as an alias.)
Terminal window
curl -X POST "https://api.postproxy.dev/api/profiles/PROFILE_ID/comments" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"parent_id": "accounts/1234/locations/5678/reviews/AbFvOq",
"body": "Thanks for the kind words!"
}'

Response (201 Created):

{
"id": "ghi789",
"external_id": null,
"parent_external_id": "accounts/1234/locations/5678/reviews/AbFvOq",
"placement_id": "accounts/1234/locations/5678",
"body": "Thanks for the kind words!",
"status": "pending",
"author_username": null,
"author_avatar_url": null,
"platform_data": null,
"posted_at": null,
"created_at": "2026-05-13T10:30:00Z"
}

DELETE /api/profiles/:profile_id/comments/:id

Deletes your reply to a review. Neither platform lets businesses delete reviews themselves — the original review row stays.

ParameterTypeRequiredDescription
profile_idstringYesProfile ID
idstringYesComment ID or external ID
Terminal window
curl -X DELETE "https://api.postproxy.dev/api/profiles/PROFILE_ID/comments/COMMENT_ID" \
-H "Authorization: Bearer YOUR_API_KEY"

Response (200 OK):

{
"accepted": true
}

The profile_comment.created event fires whenever a new profile comment record appears — both for newly synced incoming reviews and for outgoing replies that have just been published. Subscribe to profile_comment.created (or *) under your webhook endpoint’s events list. See the Webhooks reference for delivery, retries, and signature verification.

profile_comment.created fires once per new review across all locations of the account. Webhook registration does not currently offer a placement filter — subscribers with multi-location accounts should filter on data.object.placement_id themselves.

profile_comment.deleted carries the same payload with status: "deleted" and fires when a synced Google Business review or owner reply is no longer present on Google. Subscribe to it (or *) to keep a mirror in sync.

Sample payload (data.object holds the comment; see Webhooks · Event payload for the envelope):

{
"id": "whevt_p9k4j7",
"object": "event",
"type": "profile_comment.created",
"created_at": "2026-05-13T06:00:01Z",
"data": {
"object": {
"id": "abc123",
"profile_id": "prof123abc",
"platform": "google_business",
"placement_id": "accounts/1234/locations/5678",
"external_id": "accounts/1234/locations/5678/reviews/AbFvOq",
"parent_external_id": null,
"body": "Great coffee, friendly staff!",
"status": "synced",
"error": null,
"error_details": null,
"author_username": "Jane D.",
"author_avatar_url": "https://lh3.googleusercontent.com/...",
"platform_data": { "star_rating": 5, "update_time": "2026-05-10T12:00:00Z", "review_reply_url": "https://business.google.com/..." },
"permalink": "https://search.google.com/local/reviews?placeid=ChIJxyz",
"posted_at": "2026-05-10T11:55:00Z",
"created_at": "2026-05-13T06:00:01Z"
}
}
}

FieldTypeDescription
idstringPostproxy comment ID (hashid)
external_idstring|nullPlatform’s native resource ID (null while a reply is pending publication)
parent_external_idstring|nullExternal ID of parent review (null for top-level reviews)
placement_idstringLocation path (e.g. accounts/X/locations/Y) for Google Business; Page ID for Facebook
bodystringComment/review text
statusstringOne of synced, pending, published, failed, failed_waiting_for_retry, deleted
errorstring|nullError summary if an outgoing reply failed (null otherwise)
error_detailsobject|nullStructured platform error (omitted when no platform error info is available)
error_details.platform_error_codestring|nullError code returned by the platform API
error_details.platform_error_subcodestring|nullError subcode returned by the platform API
error_details.platform_error_messagestring|nullError message returned by the platform API
error_details.postproxy_notestring|nullAdditional context from Postproxy about the error
author_usernamestring|nullDisplay name of reviewer (null for your own replies, and always null on Facebook)
author_avatar_urlstring|nullProfile image URL
platform_dataobject|nullPlatform-specific metadata (e.g. star_rating, update_time, review_reply_url for Google reviews; reply_state and policy_violation on Google replies — see Google Business specifics; recommendation_type for Facebook recommendations)
permalinkstring|nullURL to the comment on the platform (the location’s reviews page on Google or the Page’s reviews tab on Facebook; null if unavailable)
posted_atstring|nullISO 8601 timestamp of platform posting
created_atstringISO 8601 timestamp of record creation
repliesarrayNested replies to this comment (present on list/get responses)
StatusDescription
syncedReview fetched from the platform during sync
pendingReply created via API, awaiting publication
publishedReply successfully posted to the platform
failedReply failed to publish
failed_waiting_for_retryReply failed and is queued for retry
deletedReview or reply no longer exists on the platform (Google Business). Excluded from list responses, still fetchable by id

Missing parent_id (422):

{
"error": "parent_id is required"
}

Unsupported method (405):

{
"error": "Unsupported method for instagram"
}

Not found (404):

{
"error": "Not found"
}

Bad request (400):

{
"error": "param is missing or the value is empty"
}