Every API here is available over the APIs.io API and to AI agents over MCP.
openapi: 3.2.0
info:
title: Prisma Reviews Connections API
version: 1.0.0
summary: One REST API to read and reply to reviews on the App Store, Google Play, Yelp, Tripadvisor and more.
description: 'Read the reviews of the businesses and apps you own or manage on the App Store, Google Play, Judge.me, eBay, Trusted Shops, eKomi, Yelp, Tripadvisor, Booking.com, G2 and 50+ more platforms, all in one normalized JSON shape, and reply through each platform''s official API where it has one (read-only platforms return the link where a review is answered). Google Business Profile, Trustpilot, Allegro, Etsy, Angi and Mercado Libre are coming soon: `GET /v1/platforms` says which platforms are ready (`live_ready`).
- **Auth:** `Authorization: Bearer `. Live keys (`pk_live_…`) work with real accounts; test keys (`pk_test_…`) connect any platform with sample locations and reviews and never publish replies. Test and live data never mix.
- **Format:** JSON in and out; timestamps are ISO 8601 in UTC; IDs are prefixed (`rev_`, `loc_`, `con_`, `we_`, `evt_`, `req_`).
- **Pagination:** `GET /v1/reviews` is cursor paginated (`data` + `next_cursor`).
- **Rate limits:** per key and per minute, set by the plan (Spark 60, Beam 120, Spectrum 600, Aurora 1,200), reported in `X-RateLimit-Limit` and `X-RateLimit-Remaining`.
- **Errors:** one shape, `{ "error": { "type", "code", "message", "retryable", "request_id", "docs_url" } }`; codes on https://prismareviews.com/docs/errors.
- **Webhooks:** signed `POST`s for new and updated reviews, published or failed replies and connection changes.
Get a free API key at https://app.prismareviews.com/signup.'
termsOfService: https://prismareviews.com/terms
contact:
name: Prisma Reviews
url: https://prismareviews.com
email: hello@prismareviews.com
x-logo:
url: https://prismareviews.com/favicon.svg
altText: Prisma Reviews
servers:
- url: https://api.prismareviews.com
description: Production (live and test keys)
security:
- apiKey: []
tags:
- name: Connections
description: Connect platform accounts by OAuth, credentials or listing URL, or with a connect link.
externalDocs:
description: Docs
url: https://prismareviews.com/docs/api-reference/connections
paths:
/v1/connections:
post:
operationId: createConnection
tags:
- Connections
summary: Create a connection
description: 'Connects one platform account and imports its locations. How depends on the platform (see `GET /v1/platforms`): `oauth` platforms need `redirect_url` and return `status: "pending"` with an `authorization_url` for the owner; `credentials` platforms need `credentials`, which Prisma tries against the platform before storing anything; `listing_url` platforms need the public `listing_url` of the listing. With a test key any platform connects at once, without credentials, with sample locations and reviews. Locations over the plan limit are not created and are counted in `locations_over_plan_limit`. Not idempotent: retrying creates a second connection.'
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/ConnectionInput'
examples:
oauth:
summary: OAuth (Google Business Profile)
value:
platform: google
redirect_url: https://yourapp.com/prisma/callback
metadata:
client: acme
credentials:
summary: Credentials (Judge.me)
value:
platform: judge_me
credentials:
shop_domain: example-store.myshopify.com
api_token: your-judge-me-api-token
listing_url:
summary: Listing URL (Yelp)
value:
platform: yelp
listing_url: https://www.yelp.com/biz/example-cafe-san-francisco
test:
summary: Any platform with a test key
value:
platform: trustpilot
responses:
'201':
description: The new connection, plus `authorization_url` (OAuth) or `locations_created` and `locations_over_plan_limit`.
headers:
Request-Id:
$ref: '#/components/headers/Request-Id'
X-RateLimit-Limit:
$ref: '#/components/headers/X-RateLimit-Limit'
X-RateLimit-Remaining:
$ref: '#/components/headers/X-RateLimit-Remaining'
content:
application/json:
schema:
$ref: '#/components/schemas/ConnectionCreated'
example:
id: con_01KJ8P7R5S3T1V9W7X5Y3Z1A2B
platform: google
status: pending
metadata:
client: acme
created_at: '2026-10-21T08:55:00.000Z'
updated_at: '2026-10-21T08:55:00.000Z'
authorization_url: https://accounts.google.com/o/oauth2/v2/auth?client_id=...&state=...
'401':
$ref: '#/components/responses/Unauthorized'
'403':
description: The platform isn't in your plan (`plan_feature_unavailable`, with `platform`, `feature` and `upgrade_url`), isn't enabled for your account yet (`platform_not_enabled`), or the account is suspended (`account_suspended`).
headers:
Request-Id:
$ref: '#/components/headers/Request-Id'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
examples:
plan_feature_unavailable:
value:
error:
type: permission_error
code: plan_feature_unavailable
message: 'Yelp isn''t included in the free Spark plan: it starts at Beam, or add a read pack to Spark from the Plan page.'
retryable: false
request_id: req_01KJ8T3C5D7E9F1G3H5J7K9M1N
docs_url: https://prismareviews.com/docs/errors#plan_feature_unavailable
platform: yelp
feature: platform
upgrade_url: https://app.prismareviews.com/plan
platform_not_enabled:
value:
error:
type: permission_error
code: platform_not_enabled
message: G2 isn't available for your account yet. Write to hello@prismareviews.com to get early access.
retryable: false
request_id: req_01KJ8T3C5D7E9F1G3H5J7K9M1N
docs_url: https://prismareviews.com/docs/errors#platform_not_enabled
platform: g2
account_suspended:
value:
error:
type: permission_error
code: account_suspended
message: This account is suspended. Write to hello@prismareviews.com.
retryable: false
request_id: req_01KJ8T3C5D7E9F1G3H5J7K9M1N
docs_url: https://prismareviews.com/docs/errors#account_suspended
'422':
description: Unknown `platform` (with `platforms_url`), a missing `redirect_url`, `credentials` or `listing_url`, a listing URL from another site or a body that isn't valid JSON (`invalid_request`); credentials with the wrong shape or rejected by the platform (`invalid_credentials`). Errors about a known platform carry `required_fields`, `example` and `setup`.
headers:
Request-Id:
$ref: '#/components/headers/Request-Id'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
examples:
invalid_request:
value:
error:
type: invalid_request_error
code: invalid_request
message: 'listing_url is required to connect Yelp: the public page of the listing.'
retryable: false
request_id: req_01KJ8T3C5D7E9F1G3H5J7K9M1N
docs_url: https://prismareviews.com/docs/errors#invalid_request
platform: yelp
required_fields:
- listing_url
example:
platform: yelp
listing_url: https://www.yelp.com/biz/example-cafe-madrid
setup: https://api.prismareviews.com/v1/platforms/yelp
invalid_credentials:
value:
error:
type: invalid_request_error
code: invalid_credentials
message: 'Judge.me rejected these credentials: invalid api token'
retryable: false
request_id: req_01KJ8T3C5D7E9F1G3H5J7K9M1N
docs_url: https://prismareviews.com/docs/errors#invalid_credentials
platform: judge_me
required_fields:
- credentials.shop_domain
- credentials.api_token
example:
platform: judge_me
credentials:
shop_domain: example-store.myshopify.com
api_token: …
setup: https://api.prismareviews.com/v1/platforms/judge_me
'429':
$ref: '#/components/responses/RateLimited'
'500':
$ref: '#/components/responses/InternalError'
'501':
description: 'The platform can''t be connected with live keys yet (`live_ready: false` in `GET /v1/platforms`). Test keys work.'
headers:
Request-Id:
$ref: '#/components/headers/Request-Id'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
examples:
platform_not_available:
value:
error:
type: api_error
code: platform_not_available
message: Trustpilot isn't open yet with live keys. It opens soon; meanwhile a test key shows how it works.
retryable: true
request_id: req_01KJ8T3C5D7E9F1G3H5J7K9M1N
docs_url: https://prismareviews.com/docs/errors#platform_not_available
platform: trustpilot
'503':
$ref: '#/components/responses/Maintenance'
externalDocs:
description: Docs
url: https://prismareviews.com/docs/api-reference/connections
get:
operationId: listConnections
tags:
- Connections
summary: List connections
description: 'Every connection of your workspace in the mode of your key, oldest first, including `pending`, `reauth_required` and `disconnected` ones. Not paginated: `next_cursor` is always `null`.'
responses:
'200':
description: All connections.
headers:
Request-Id:
$ref: '#/components/headers/Request-Id'
X-RateLimit-Limit:
$ref: '#/components/headers/X-RateLimit-Limit'
X-RateLimit-Remaining:
$ref: '#/components/headers/X-RateLimit-Remaining'
content:
application/json:
schema:
$ref: '#/components/schemas/ConnectionList'
example:
data:
- id: con_01KJ8P7R5S3T1V9W7X5Y3Z1A2B
platform: google
status: active
metadata:
client: acme
created_at: '2026-10-21T08:55:00.000Z'
updated_at: '2026-10-21T08:56:41.000Z'
next_cursor: null
'401':
$ref: '#/components/responses/Unauthorized'
'403':
$ref: '#/components/responses/Forbidden'
'429':
$ref: '#/components/responses/RateLimited'
'500':
$ref: '#/components/responses/InternalError'
'503':
$ref: '#/components/responses/Maintenance'
externalDocs:
description: Docs
url: https://prismareviews.com/docs/api-reference/connections
/v1/connections/{id}:
delete:
operationId: deleteConnection
tags:
- Connections
summary: Delete a connection
description: 'Disconnects the connection: its stored tokens and credentials are deleted at once and its locations become `disconnected` (no more checks, not counted toward the plan). Their reviews stay readable for 30 days and are then deleted. To reauthorize a connection, delete it and create a new one.'
parameters:
- name: id
in: path
required: true
description: Connection ID (`con_…`).
schema:
type: string
example: con_01KJ8P7R5S3T1V9W7X5Y3Z1A2B
responses:
'200':
description: The disconnected connection, plus `locations_disconnected`.
headers:
Request-Id:
$ref: '#/components/headers/Request-Id'
X-RateLimit-Limit:
$ref: '#/components/headers/X-RateLimit-Limit'
X-RateLimit-Remaining:
$ref: '#/components/headers/X-RateLimit-Remaining'
content:
application/json:
schema:
$ref: '#/components/schemas/ConnectionDeleted'
example:
id: con_01KJ8P7R5S3T1V9W7X5Y3Z1A2B
platform: google
status: disconnected
metadata:
client: acme
created_at: '2026-10-21T08:55:00.000Z'
updated_at: '2026-10-21T08:56:41.000Z'
locations_disconnected: 3
'401':
$ref: '#/components/responses/Unauthorized'
'403':
$ref: '#/components/responses/Forbidden'
'404':
description: No connection with that ID in this workspace and mode (`resource_not_found`).
headers:
Request-Id:
$ref: '#/components/headers/Request-Id'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
examples:
resource_not_found:
value:
error:
type: not_found_error
code: resource_not_found
message: No connection with that id in this workspace.
retryable: false
request_id: req_01KJ8T3C5D7E9F1G3H5J7K9M1N
docs_url: https://prismareviews.com/docs/errors#resource_not_found
'429':
$ref: '#/components/responses/RateLimited'
'500':
$ref: '#/components/responses/InternalError'
'503':
$ref: '#/components/responses/Maintenance'
externalDocs:
description: Docs
url: https://prismareviews.com/docs/api-reference/connections
/v1/connect_links:
post:
operationId: createConnectLink
tags:
- Connections
summary: Create a connect link
description: 'A link the owner of a platform account opens to connect it in their browser, with no Prisma account or API key. Connections made through it belong to your workspace and to the mode of the key that created the link, and carry `metadata: {"via": "connect_link"}`. Valid for 7 days and reusable: treat it like a password-reset link. The body is optional.'
requestBody:
required: false
content:
application/json:
schema:
type: object
additionalProperties: true
properties:
platform:
$ref: '#/components/schemas/PlatformId'
description: Only this platform. Without it, the owner chooses among the platforms of your plan.
redirect_url:
type: string
format: uri
description: Where to send the owner when they are done, with `connection_id` and `status` added to the query string. Must start with `https://` (or `http://localhost` for development).
example:
platform: google
redirect_url: https://yourapp.com/connected
responses:
'201':
description: The connect link.
headers:
Request-Id:
$ref: '#/components/headers/Request-Id'
X-RateLimit-Limit:
$ref: '#/components/headers/X-RateLimit-Limit'
X-RateLimit-Remaining:
$ref: '#/components/headers/X-RateLimit-Remaining'
content:
application/json:
schema:
$ref: '#/components/schemas/ConnectLink'
example:
url: https://app.prismareviews.com/connect/cl_eyJ3Ijoid3NfMDFL…
platform: google
mode: live
expires_at: '2026-11-02T17:40:00.000Z'
'401':
$ref: '#/components/responses/Unauthorized'
'403':
$ref: '#/components/responses/Forbidden'
'422':
description: Unknown `platform`, or a `redirect_url` that isn't a URL or doesn't use https (`invalid_request`).
headers:
Request-Id:
$ref: '#/components/headers/Request-Id'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
examples:
invalid_request:
value:
error:
type: invalid_request_error
code: invalid_request
message: 'limit: Number must be less than or equal to 100'
retryable: false
request_id: req_01KJ8T3C5D7E9F1G3H5J7K9M1N
docs_url: https://prismareviews.com/docs/errors#invalid_request
'429':
$ref: '#/components/responses/RateLimited'
'500':
$ref: '#/components/responses/InternalError'
'503':
$ref: '#/components/responses/Maintenance'
externalDocs:
description: Docs
url: https://prismareviews.com/docs/api-reference/connections#connect-links
components:
responses:
InternalError:
description: Something failed on Prisma's side. Retryable.
headers:
Request-Id:
$ref: '#/components/headers/Request-Id'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
examples:
internal_error:
value:
error:
type: api_error
code: internal_error
message: Something went wrong on our side. It has been logged; try again.
retryable: true
request_id: req_01KJ8T3C5D7E9F1G3H5J7K9M1N
docs_url: https://prismareviews.com/docs/errors#internal_error
RateLimited:
description: More requests this minute than the plan allows for this key. Not counted in usage.
headers:
Request-Id:
$ref: '#/components/headers/Request-Id'
Retry-After:
$ref: '#/components/headers/Retry-After'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
examples:
rate_limited:
value:
error:
type: rate_limit_error
code: rate_limited
message: Rate limit of 60 requests per minute exceeded. Retry in 12 s. Requests over the limit are never billed.
retryable: true
request_id: req_01KJ8T3C5D7E9F1G3H5J7K9M1N
docs_url: https://prismareviews.com/docs/errors#rate_limited
Unauthorized:
description: No API key or one not shaped like a Prisma key (`missing_api_key`), or a key that doesn't exist or was revoked (`invalid_api_key`).
headers:
Request-Id:
$ref: '#/components/headers/Request-Id'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
examples:
missing_api_key:
value:
error:
type: authentication_error
code: missing_api_key
message: 'Send your API key as "Authorization: Bearer pk_live_…".'
retryable: false
request_id: req_01KJ8T3C5D7E9F1G3H5J7K9M1N
docs_url: https://prismareviews.com/docs/errors#missing_api_key
invalid_api_key:
value:
error:
type: authentication_error
code: invalid_api_key
message: This API key does not exist or was revoked.
retryable: false
request_id: req_01KJ8T3C5D7E9F1G3H5J7K9M1N
docs_url: https://prismareviews.com/docs/errors#invalid_api_key
Forbidden:
description: The account is suspended.
headers:
Request-Id:
$ref: '#/components/headers/Request-Id'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
examples:
account_suspended:
value:
error:
type: permission_error
code: account_suspended
message: This account is suspended. Write to hello@prismareviews.com.
retryable: false
request_id: req_01KJ8T3C5D7E9F1G3H5J7K9M1N
docs_url: https://prismareviews.com/docs/errors#account_suspended
Maintenance:
description: Prisma is under maintenance and the API is paused. Retryable.
headers:
Request-Id:
$ref: '#/components/headers/Request-Id'
Retry-After:
$ref: '#/components/headers/Retry-After'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
examples:
maintenance:
value:
error:
type: api_error
code: maintenance
message: Prisma is under maintenance. Try again in a few minutes; see https://prismareviews.com/status.
retryable: true
request_id: req_01KJ8T3C5D7E9F1G3H5J7K9M1N
docs_url: https://prismareviews.com/docs/errors#maintenance
schemas:
ConnectionDeleted:
allOf:
- $ref: '#/components/schemas/Connection'
- type: object
required:
- locations_disconnected
properties:
locations_disconnected:
type: integer
description: How many locations were disconnected.
ConnectLink:
type: object
required:
- url
- platform
- mode
- expires_at
properties:
url:
type: string
description: The link to send to the account owner.
format: uri
platform:
oneOf:
- $ref: '#/components/schemas/PlatformId'
- type: 'null'
description: The only platform the link connects, or `null` for any of the plan.
mode:
type: string
enum:
- live
- test
description: 'Mode of the connections it creates: that of the key.'
expires_at:
type: string
format: date-time
description: When the link stops working (7 days after creation).
ConnectionList:
type: object
required:
- data
- next_cursor
properties:
data:
type: array
items:
$ref: '#/components/schemas/Connection'
next_cursor:
type: 'null'
description: 'Always `null`: not paginated.'
Error:
type: object
required:
- error
description: Every error has this shape. Some codes add fields (for example `platform`, `url`, `max_length`, `connection_id`, `upgrade_url`, `required_fields`).
properties:
error:
type: object
required:
- type
- code
- message
- retryable
- request_id
- docs_url
additionalProperties: true
properties:
type:
type: string
enum:
- authentication_error
- permission_error
- not_found_error
- conflict_error
- invalid_request_error
- rate_limit_error
- api_error
description: Family of the error, from the HTTP status.
code:
type: string
description: Stable, machine-readable code. Branch on this, not on `message`.
message:
type: string
description: Human-readable explanation. It can change.
retryable:
type: boolean
description: '`true` for 429 and 5xx: the same request can succeed later.'
request_id:
type: string
description: The `req_…` ID, also in the `Request-Id` header.
docs_url:
type: string
description: Description of this code.
format: uri
PlatformId:
type: string
enum:
- google
- app_store
- google_play
- judge_me
- trustpilot
- google_maps
- yelp
- tripadvisor
- booking
- yotpo
- reviews_io
- g2
- ebay
- etsy
- steam
- okendo
- feefo
- trusted_shops
- ekomi
- loox
- proven_expert
- shopper_approved
- wordpress
- appexchange
- facebook
- opentable
- doordash
- angi
- checkatrade
- avvo
- capterra
- apartments
- gartner
- healthgrades
- vitals
- classpass
description: 'Platform ID.
| ID | Platform | Connects with | Replies |
| --- | --- | --- | --- |
| `google` | Google Business Profile | oauth | by API |
| `app_store` | App Store | credentials | by API |
| `google_play` | Google Play | credentials | by API |
| `judge_me` | Judge.me | credentials | by API |
| `trustpilot` | Trustpilot | oauth | by API |
| `google_maps` | Google Maps | listing_url | read only |
| `yelp` | Yelp | listing_url | read only |
| `tripadvisor` | Tripadvisor | listing_url | read only |
| `booking` | Booking.com | listing_url | read only |
| `yotpo` | Yotpo | credentials | read only |
| `reviews_io` | REVIEWS.io | credentials | read only |
| `g2` | G2 | credentials | read only |
| `ebay` | eBay | oauth | by API |
| `etsy` | Etsy | listing_url | read only |
| `steam` | Steam | listing_url | read only |
| `okendo` | Okendo | credentials | read only |
| `feefo` | Feefo | credentials | read only |
| `trusted_shops` | Trusted Shops | credentials | by API |
| `ekomi` | eKomi | credentials | by API |
| `loox` | Loox | credentials | read only |
| `proven_expert` | ProvenExpert | credentials | read only |
| `shopper_approved` | Shopper Approved | credentials | read only |
| `wordpress` | WordPress.org | listing_url | read only |
| `appexchange` | Salesforce AppExchange | listing_url | read only |
| `facebook` | Facebook | listing_url | read only |
| `opentable` | OpenTable | listing_url | read only |
| `doordash` | DoorDash | listing_url | read only |
| `angi` | Angi | listing_url | read only |
| `checkatrade` | Checkatrade | listing_url | read only |
| `avvo` | Avvo | listing_url | read only |
| `capterra` | Capterra | listing_url | read only |
| `apartments` | Apartments.com | listing_url | read only |
| `gartner` | Gartner Peer Insights | listing_url | read only |
| `healthgrades` | Healthgrades | listing_url | read only |
| `vitals` | Vitals | listing_url | read only |
| `classpass` | ClassPass | listing_url | read only |'
Connection:
type: object
required:
- id
- platform
- status
- metadata
- created_at
- updated_at
description: The access a business gave Prisma to its account on one platform. Credentials and tokens are never returned.
properties:
id:
type: string
description: Connection ID (`con_…`).
example: con_01KJ8P7R5S3T1V9W7X5Y3Z1A2B
platform:
$ref: '#/components/schemas/PlatformId'
status:
type: string
enum:
- pending
- active
- reauth_required
- disconnected
description: '`pending` (waiting for the owner to approve OAuth), `active`, `reauth_required` (the platform rejected the stored token or key) or `disconnected`.'
metadata:
type: object
additionalProperties: true
description: Your own key-value pairs, returned as sent.
created_at:
type: string
format: date-time
description: When it was created.
updated_at:
type: string
format: date-time
description: When it last changed.
ConnectionInput:
type: object
required:
- platform
additionalProperties: true
properties:
platform:
$ref: '#/components/schemas/PlatformId'
description: Platform to connect. An unknown value returns `422 invalid_request`.
redirect_url:
type: string
format: uri
description: 'Required for `oauth` platforms (live keys): where the owner lands after approving, with `connection_id` and `status` in the query string.'
credentials:
type: object
additionalProperties: true
description: Required for `credentials` platforms, and for Trustpilot (`domain`). Fields per platform in `GET /v1/platforms`.
listing_url:
type: string
format: uri
description: 'Required for `listing_url` platforms: the public page of the listing.'
metadata:
type: object
additionalProperties: true
description: Your own key-value pairs, for example your client ID.
ConnectionCreated:
allOf:
- $ref: '#/components/schemas/Connection'
- type: object
properties:
authorization_url:
type: string
format: uri
description: '`oauth` platforms with a live key: send the account owner here to approve access.'
locations_created:
type: integer
description: Locations imported (credentials, listing URL and test connections).
locations_over_plan_limit:
type: integer
description: Locations not imported because of the plan limit.
headers:
X-RateLimit-Remaining:
description: Requests left in the current one-minute window.
schema:
type: integer
Request-Id:
description: The `req_…` ID of the request. Include it when you contact support.
schema:
type: string
Retry-After:
description: Seconds to wait before retrying.
schema:
type: integer
X-RateLimit-Limit:
description: Requests allowed per minute for this key.
schema:
type: integer
securitySchemes:
apiKey:
type: http
scheme: bearer
bearerFormat: pk_live_… / pk_test_…
description: 'Your secret API key as a Bearer token: `pk_live_…` for real accounts, `pk_test_…` for sample data. Keep it on your server.'
externalDocs:
description: Prisma Reviews API reference
url: https://prismareviews.com/docs/api-reference