Developer reference

SyncMyReviews Zapier API

This is the complete REST surface the SyncMyReviews app on Zapier calls. It covers authentication, the seven REST-hook triggers, two searches, four write actions, and the dropdowns that populate the Zap editor. Everything here is read-only reference material — no account is required to view it.

Overview

All Zapier endpoints live under the /api/zapier prefix on the production API host. There is no sandbox tier: the integration talks to production only.

Base URLhttps://api.syncmyreviews.com
TransportHTTPS only. Plain HTTP is not served.
Content typeapplication/json for request and response bodies.
TimestampsISO 8601, UTC.
TenancyEvery query is scoped to the account that owns the token. An id belonging to another account is indistinguishable from one that does not exist — both return 404.

Google and Facebook are connected on the SyncMyReviews side. The Zapier app never talks to those platforms directly; it only calls the endpoints on this page.

Authentication

The integration uses a SyncMyReviews-issued API token sent as a bearer credential. Account owners mint the token from Connections → Zapier in the dashboard; the plaintext value is shown exactly once and is stored only as a hash. Members cannot generate tokens.

Authorization: Bearer <syncmyreviews-token>
Accept: application/json

A token carries two abilities. Read endpoints (including subscribe and unsubscribe) require zapier:read; the four write actions additionally require zapier:write.

GET /api/zapier/auth/test

Called immediately after the user pastes a token. A 200 confirms the credential, and connection_label is what Zapier shows as the connection name.

{
  "account_id": 1234,
  "account_name": "Acme Coffee Group",
  "connection_label": "Acme Coffee Group",
  "token_last_four": "k9Xz",
  "abilities": ["zapier:read", "zapier:write"]
}

Revoking or rotating the token from the dashboard invalidates it immediately; subsequent calls return 401 and Zapier prompts the user to reconnect.

Error format

Every error uses one envelope: a stable machine error code, a message safe to show to the Zap builder, and an optional context object. The context key is omitted when empty.

{
  "error": "subscription_inactive",
  "message": "This business does not have an active subscription.",
  "context": { "business_id": 521 }
}
CodeHTTPWhen it happens
missing_token401No bearer token was sent.
invalid_token401The token does not resolve to an account.
token_revoked401The token was revoked or has expired.
ability_missing403The token lacks the ability the route requires.
validation_failed422The payload failed validation. Field errors are nested under context.errors.
subscription_inactive402The target business has no active or trialing subscription.
business_not_found404The business id is unknown or belongs to another account.
review_not_found404The review id is unknown or belongs to another account.
subscription_not_found404The hook subscription id is unknown or belongs to another account.
missing_google_connection409The business has no connected Google location.
missing_facebook_connection409The business has no connected Facebook page.
rate_limit_exceeded429The per-token action rate limit was exhausted.
payload_too_large413The request body exceeded the size cap.
internal_error500An unexpected server error. No stack trace is ever returned.

Validation failures nest Laravel's field-level messages under context.errors, keyed by field name, so Zapier can surface them verbatim.

Endpoint index

MethodURIAbilityPurpose
GET/api/zapier/auth/testzapier:readVerify a token and return the connection label.
GET/api/zapier/businesseszapier:readBusiness dropdown, including subscription state.
GET/api/zapier/tagszapier:readTag dropdown for the account.
GET/api/zapier/sourceszapier:readReview-source dropdown (server-side constant list).
POST/api/zapier/triggers/{triggerKey}/subscriptionszapier:readSubscribe a Zap to a trigger (REST hook).
DELETE/api/zapier/triggers/{triggerKey}/subscriptions/{subscriptionId}zapier:readUnsubscribe a Zap from a trigger.
GET/api/zapier/triggers/{triggerKey}/samplezapier:readSingle sample event for Zapier's test step.
GET/api/zapier/searches/businesseszapier:readFind a business by name or exact slug.
GET/api/zapier/searches/reviewszapier:readFind a review by source and external id.
POST/api/zapier/actions/manual-reviewszapier:writeCreate a manual review.
PATCH/api/zapier/actions/reviews/{reviewId}/visibilityzapier:writeHide or show a review.
POST/api/zapier/actions/google-postszapier:writeSchedule a Google Business Profile post.
POST/api/zapier/actions/facebook-postszapier:writeSchedule a Facebook Page post.

These three endpoints populate the pickers in the Zap editor. All of them return a data envelope.

GET /api/zapier/businesses

Every business under the account, including those whose subscription has lapsed, so a user can see that a Zap is wired up even when it will not fire yet. display_label is the string Zapier renders.

{
  "data": [
    {
      "id": 521,
      "name": "Acme Coffee — Downtown",
      "has_active_subscription": true,
      "display_label": "Acme Coffee — Downtown"
    },
    {
      "id": 522,
      "name": "Acme Coffee — Suburb",
      "has_active_subscription": false,
      "display_label": "Acme Coffee — Suburb (— Subscription inactive)"
    }
  ]
}

GET /api/zapier/tags and GET /api/zapier/sources

Both return generic { id, label } items. Tags are the account's own review tags. Sources are a fixed list served from the API so a new source never requires a new app version.

{
  "data": [
    { "id": "google",            "label": "Google" },
    { "id": "facebook",          "label": "Facebook" },
    { "id": "manual",            "label": "Manual" },
    { "id": "pipeline_negative", "label": "Negative Pipeline Feedback" }
  ]
}

Triggers (REST hooks)

Triggers are push-based REST hooks, not polling. A Zap subscribes once, and SyncMyReviews POSTs to the Zap's hook URL whenever the event occurs. Seven trigger keys are available.

Trigger keyNameFires when
new_reviewNew reviewAny new Google, Facebook, or manual review on the selected business.
new_low_rating_reviewNew low-rating reviewA new review whose numeric rating is 3 or lower.
new_five_star_reviewNew five-star reviewA new review whose numeric rating is exactly 5.
new_negative_pipeline_feedbackNew negative pipeline feedbackA review-pipeline visitor submits a low rating into the private feedback branch.
review_modified_upstreamReview modified upstreamA previously synced Google or Facebook review changes its text or rating upstream.
qr_code_scannedQR code scannedOne of the business's review QR codes is scanned.
scheduled_post_outcomeScheduled post outcomeA scheduled Google or Facebook post publishes or fails.

A single new review can resolve to more than one trigger: a 1-star review fires both new_review and new_low_rating_review. A Facebook recommendation with no numeric rating fires only new_review, because a missing rating is never coerced into a rating band.

POST /api/zapier/triggers/{triggerKey}/subscriptions

Request body:

{
  "business_id": 521,
  "target_url": "https://hooks.zapier.com/hooks/catch/123/abc"
}

target_url must be HTTPS and its host must sit under an allow-listed Zapier domain (zapier.com or zapierusercontent.com); anything else is rejected as a field-level validation error. The optional filters key is reserved for a future version and must be absent or empty. Responds 201:

{
  "id": 9001,
  "trigger_key": "new_review",
  "business_id": 521,
  "expires_at": null
}

Subscribing is idempotent: repeating the same trigger key and target URL returns the existing subscription rather than creating a duplicate. Subscribing to a business whose subscription has lapsed is allowed on purpose — the Zap registers and simply stays quiet until billing is active again.

DELETE /api/zapier/triggers/{triggerKey}/subscriptions/{subscriptionId}

Soft-revokes the subscription and responds 204 with an empty body. An unknown id, or one owned by another account, returns 404 subscription_not_found.

GET /api/zapier/triggers/{triggerKey}/sample

Returns a single-element array holding one representative event for the trigger, so Zapier's test step always has data to map even on a brand-new account. Each item carries a top-level id for deduplication. An unrecognised trigger key returns 422 validation_failed.

Outbound payloads

Every outbound event shares one envelope. The data block is the only part that varies by trigger.

{
  "_schema_version": 1,
  "event": "new_review",
  "event_id": "evt_01HXY9...",
  "occurred_at": "2026-05-14T18:42:11Z",
  "business": {
    "id": 521,
    "name": "Acme Coffee — Downtown",
    "slug": "acme-coffee-downtown",
    "timezone": "Europe/Belgrade"
  },
  "data": {
    "source": "google",
    "external_id": "AbF...xyz",
    "rating": 5,
    "rating_normalised_1_5": 5,
    "review_text": "Best coffee in town.",
    "author_name": "Jane Doe",
    "posted_at": "2026-05-14T18:40:02Z",
    "review_url": null,
    "is_hidden": false,
    "tags": []
  }
}

event_id is generated server-side and is stable, so a Zap can deduplicate on it. A few field-level details matter when you build downstream steps:

  • review_url is optional. Facebook reviews carry a permalink; Google, manual, and pipeline reviews send null. Treat it as nullable, never as always present.
  • rating can be null on Facebook. Recommendation-only reviews have no star rating, but rating_normalised_1_5 is always populated (recommended maps to 5, not recommended maps to 1).
  • QR scan IPs are truncated. The full visitor IP never leaves the platform — it is reduced to a /24 prefix for IPv4 or a /48 prefix for IPv6.
  • Pipeline submitter emails are never sent. They exist in SyncMyReviews but are excluded from every outbound payload.
  • Post failures use a stable reason code. failure_reason is an enum rather than raw upstream error text, so provider error strings can never leak through.
  • Payloads are size-capped. Oversized events have their long text fields trimmed and flagged rather than being sent oversized.

Searches

Searches follow Zapier's conventions: results are a bare top-level array, and no match is an empty array with 200 — never a 404.

GET /api/zapier/searches/businesses?query=

Matches up to 25 businesses by case-insensitive partial name or by exact slug. Wildcard characters typed by the user are matched literally.

[
  { "id": 521, "name": "Acme Coffee — Downtown", "slug": "acme-coffee-downtown" }
]

GET /api/zapier/searches/reviews?source=&external_id=

Returns zero or one match. source accepts google, facebook, or manual. Manual reviews have no upstream id, so that source always returns an empty array; pipeline_negative is not searchable and is rejected with 422.

[
  {
    "id": 88421,
    "source": "google",
    "external_id": "AbF...xyz",
    "business_id": 521,
    "rating": 5,
    "review_text": "Best coffee in town.",
    "author_name": "Jane Doe",
    "is_hidden": false,
    "posted_at": "2026-05-14T18:40:02Z"
  }
]

Actions

POST /api/zapier/actions/manual-reviews

Records an external survey result as a manual review alongside Google and Facebook reviews.

FieldRules
business_idRequired integer.
author_nameRequired string, max 200 characters.
author_emailOptional email, max 200 characters.
ratingRequired integer between 1 and 5.
review_textRequired string, max 5000 characters.

Responds 201:

{
  "review_id": 88421,
  "source": "manual",
  "business_id": 521,
  "author_name": "Jane Doe",
  "rating": 4,
  "review_text": "Survey response imported from Typeform.",
  "created_at": "2026-05-14T18:50:00+00:00"
}

PATCH /api/zapier/actions/reviews/{reviewId}/visibility

Hides or shows a review across the public widgets, badges, and trust card. Requires source (google, facebook, or manual) and a boolean hidden. An unknown or cross-account review id returns 404 review_not_found.

{
  "review_id": 88421,
  "source": "google",
  "business_id": 521,
  "hidden": true,
  "updated_at": "2026-05-14T18:52:10+00:00"
}

POST /api/zapier/actions/google-posts

Queues a Google Business Profile post. The business must have a connected Google location, otherwise the call returns 409 missing_google_connection. Accepts business_id, an optional title (max 200), a required body (max 1500), optional image_url and cta_url, and a scheduled_for timestamp that must be in the future and within 90 days.

{
  "scheduled_post_id": 412,
  "platform": "google",
  "business_id": 521,
  "status": "scheduled",
  "title": "Spring promotion",
  "body": "Get 20% off all espresso drinks this week.",
  "image_url": null,
  "scheduled_for": "2026-05-20T15:00:00+00:00",
  "created_at": "2026-05-14T18:55:00+00:00"
}

POST /api/zapier/actions/facebook-posts

Same contract without title or cta_url. The business must have a connected Facebook page, otherwise the call returns 409 missing_facebook_connection. The response mirrors the Google shape with "platform": "facebook" and no title.

Limits and delivery

  • Rate limiting. Write actions are limited per token, so one busy connection can never throttle another account. Exhausting the bucket returns 429 rate_limit_exceeded.
  • Signed deliveries. Every outbound POST carries an X-Sync-Signature header of the form t=<unix-timestamp>,v1=<hex>, an HMAC-SHA256 over <timestamp>.<raw-body>. Signing keys rotate with a dual-key grace window.
  • Disabled Zaps clean themselves up. A 410 Gone from the hook URL automatically unsubscribes that hook.
  • Transient failures retry. A timeout, 429, or 5xx from the hook URL is queued and retried with exponential backoff. After the retries are exhausted the subscription is flagged for review rather than deleted.
  • Subscription gate at delivery time. Billing is re-checked when the event is dispatched, not only when it was raised. If the business's subscription has lapsed the event is skipped silently and no webhook is sent.
  • Duplicate suppression. Identical events raised within a short window for the same subscription are coalesced into a single delivery.

Get started

Account owners generate a Zapier token from Connections → Zapier in the SyncMyReviews dashboard (sign-in required). Members cannot mint tokens. Use the workflow builder below to connect SyncMyReviews to the rest of your stack without leaving this page.


LinkedIn