{
  "openapi": "3.0.0",
  "paths": {
    "/api/v1/public/me": {
      "get": {
        "operationId": "PublicMeController_me",
        "summary": "The organization, key and plan behind this key",
        "description": "Any valid key. The connection test of Zapier and Make.",
        "parameters": [],
        "responses": {
          "200": {
            "headers": {
              "X-Request-Id": {
                "description": "Unique per request; also requestId in an error body.",
                "schema": {
                  "type": "string",
                  "format": "uuid"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Requests allowed per minute per key (60). Absent while the limiter is unavailable.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requests left in the current minute. Absent while the limiter is unavailable.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix time (seconds) when the current minute ends. Absent while the limiter is unavailable.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicMe"
                }
              }
            }
          },
          "401": {
            "headers": {
              "X-Request-Id": {
                "description": "Unique per request; also requestId in an error body.",
                "schema": {
                  "type": "string",
                  "format": "uuid"
                }
              }
            },
            "description": "MISSING_KEY, INVALID_KEY, KEY_REVOKED, KEY_EXPIRED.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicError"
                }
              }
            }
          },
          "403": {
            "headers": {
              "X-Request-Id": {
                "description": "Unique per request; also requestId in an error body.",
                "schema": {
                  "type": "string",
                  "format": "uuid"
                }
              }
            },
            "description": "PLAN_REQUIRED (with requiredTier): the API is part of Pro and above. INSUFFICIENT_SCOPE: the key lacks the scope of this route. FORBIDDEN: any other refusal of access.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicError"
                }
              }
            }
          },
          "408": {
            "headers": {
              "X-Request-Id": {
                "description": "Unique per request; also requestId in an error body.",
                "schema": {
                  "type": "string",
                  "format": "uuid"
                }
              }
            },
            "description": "TIMEOUT: we did not answer in time, so the result is unknown. Retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicError"
                }
              }
            }
          },
          "429": {
            "headers": {
              "X-Request-Id": {
                "description": "Unique per request; also requestId in an error body.",
                "schema": {
                  "type": "string",
                  "format": "uuid"
                }
              },
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "description": "RATE_LIMITED: up to 60 requests a minute per key, or too many failed authentications from one IP.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicError"
                }
              }
            }
          },
          "500": {
            "headers": {
              "X-Request-Id": {
                "description": "Unique per request; also requestId in an error body.",
                "schema": {
                  "type": "string",
                  "format": "uuid"
                }
              }
            },
            "description": "INTERNAL_ERROR: retry, and quote requestId to support if it keeps failing.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicError"
                }
              }
            }
          }
        },
        "tags": [
          "Public API"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/api/v1/public/locations": {
      "get": {
        "operationId": "PublicLocationsController_list",
        "summary": "Locations of the organization",
        "description": "Scope locations:read.",
        "parameters": [],
        "responses": {
          "200": {
            "headers": {
              "X-Request-Id": {
                "description": "Unique per request; also requestId in an error body.",
                "schema": {
                  "type": "string",
                  "format": "uuid"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Requests allowed per minute per key (60). Absent while the limiter is unavailable.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requests left in the current minute. Absent while the limiter is unavailable.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix time (seconds) when the current minute ends. Absent while the limiter is unavailable.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicLocationList"
                }
              }
            }
          },
          "401": {
            "headers": {
              "X-Request-Id": {
                "description": "Unique per request; also requestId in an error body.",
                "schema": {
                  "type": "string",
                  "format": "uuid"
                }
              }
            },
            "description": "MISSING_KEY, INVALID_KEY, KEY_REVOKED, KEY_EXPIRED.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicError"
                }
              }
            }
          },
          "403": {
            "headers": {
              "X-Request-Id": {
                "description": "Unique per request; also requestId in an error body.",
                "schema": {
                  "type": "string",
                  "format": "uuid"
                }
              }
            },
            "description": "PLAN_REQUIRED (with requiredTier): the API is part of Pro and above. INSUFFICIENT_SCOPE: the key lacks the scope of this route. FORBIDDEN: any other refusal of access.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicError"
                }
              }
            }
          },
          "408": {
            "headers": {
              "X-Request-Id": {
                "description": "Unique per request; also requestId in an error body.",
                "schema": {
                  "type": "string",
                  "format": "uuid"
                }
              }
            },
            "description": "TIMEOUT: we did not answer in time, so the result is unknown. Retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicError"
                }
              }
            }
          },
          "429": {
            "headers": {
              "X-Request-Id": {
                "description": "Unique per request; also requestId in an error body.",
                "schema": {
                  "type": "string",
                  "format": "uuid"
                }
              },
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "description": "RATE_LIMITED: up to 60 requests a minute per key, or too many failed authentications from one IP.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicError"
                }
              }
            }
          },
          "500": {
            "headers": {
              "X-Request-Id": {
                "description": "Unique per request; also requestId in an error body.",
                "schema": {
                  "type": "string",
                  "format": "uuid"
                }
              }
            },
            "description": "INTERNAL_ERROR: retry, and quote requestId to support if it keeps failing.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicError"
                }
              }
            }
          }
        },
        "tags": [
          "Public API"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/api/v1/public/reviews": {
      "get": {
        "operationId": "PublicReviewsController_list",
        "summary": "Reviews of the organization, newest first",
        "description": "Scope reviews:read. Cursor pagination: pass nextCursor as cursor until it is null.",
        "parameters": [
          {
            "name": "locationId",
            "required": false,
            "in": "query",
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "name": "platform",
            "required": false,
            "in": "query",
            "schema": {
              "enum": [
                "GOOGLE",
                "FACEBOOK",
                "INSTAGRAM",
                "LINKEDIN",
                "TIKTOK",
                "YELP",
                "TRUSTPILOT",
                "TRIPADVISOR",
                "BOOKING",
                "AIRBNB",
                "G2",
                "CAPTERRA",
                "SOFTWARE_ADVICE",
                "FOURSQUARE",
                "MERCADO_LIBRE",
                "LOCAL_GUIDES"
              ],
              "type": "string"
            }
          },
          {
            "name": "status",
            "required": false,
            "in": "query",
            "schema": {
              "enum": [
                "new",
                "pending",
                "replied",
                "ignored",
                "archived"
              ],
              "type": "string"
            }
          },
          {
            "name": "minRating",
            "required": false,
            "in": "query",
            "description": "Only content with stars.",
            "schema": {
              "minimum": 1,
              "maximum": 5,
              "type": "integer"
            }
          },
          {
            "name": "maxRating",
            "required": false,
            "in": "query",
            "description": "Only content with stars.",
            "schema": {
              "minimum": 1,
              "maximum": 5,
              "type": "integer"
            }
          },
          {
            "name": "createdAfter",
            "required": false,
            "in": "query",
            "description": "Received by RevioReputation after this moment (exclusive).",
            "schema": {
              "format": "date-time",
              "type": "string"
            }
          },
          {
            "name": "reviewedAfter",
            "required": false,
            "in": "query",
            "description": "Written by the customer after this moment (exclusive).",
            "schema": {
              "format": "date-time",
              "type": "string"
            }
          },
          {
            "name": "limit",
            "required": false,
            "in": "query",
            "schema": {
              "minimum": 1,
              "maximum": 100,
              "default": 25,
              "type": "integer"
            }
          },
          {
            "name": "cursor",
            "required": false,
            "in": "query",
            "description": "nextCursor of the previous page.",
            "schema": {
              "maxLength": 512,
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "headers": {
              "X-Request-Id": {
                "description": "Unique per request; also requestId in an error body.",
                "schema": {
                  "type": "string",
                  "format": "uuid"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Requests allowed per minute per key (60). Absent while the limiter is unavailable.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requests left in the current minute. Absent while the limiter is unavailable.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix time (seconds) when the current minute ends. Absent while the limiter is unavailable.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicReviewList"
                }
              }
            }
          },
          "400": {
            "headers": {
              "X-Request-Id": {
                "description": "Unique per request; also requestId in an error body.",
                "schema": {
                  "type": "string",
                  "format": "uuid"
                }
              }
            },
            "description": "VALIDATION_FAILED: a filter is out of range or unknown. INVALID_CURSOR: start again without a cursor.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicError"
                }
              }
            }
          },
          "401": {
            "headers": {
              "X-Request-Id": {
                "description": "Unique per request; also requestId in an error body.",
                "schema": {
                  "type": "string",
                  "format": "uuid"
                }
              }
            },
            "description": "MISSING_KEY, INVALID_KEY, KEY_REVOKED, KEY_EXPIRED.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicError"
                }
              }
            }
          },
          "403": {
            "headers": {
              "X-Request-Id": {
                "description": "Unique per request; also requestId in an error body.",
                "schema": {
                  "type": "string",
                  "format": "uuid"
                }
              }
            },
            "description": "PLAN_REQUIRED (with requiredTier): the API is part of Pro and above. INSUFFICIENT_SCOPE: the key lacks the scope of this route. FORBIDDEN: any other refusal of access.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicError"
                }
              }
            }
          },
          "408": {
            "headers": {
              "X-Request-Id": {
                "description": "Unique per request; also requestId in an error body.",
                "schema": {
                  "type": "string",
                  "format": "uuid"
                }
              }
            },
            "description": "TIMEOUT: we did not answer in time, so the result is unknown. Retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicError"
                }
              }
            }
          },
          "429": {
            "headers": {
              "X-Request-Id": {
                "description": "Unique per request; also requestId in an error body.",
                "schema": {
                  "type": "string",
                  "format": "uuid"
                }
              },
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "description": "RATE_LIMITED: up to 60 requests a minute per key, or too many failed authentications from one IP.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicError"
                }
              }
            }
          },
          "500": {
            "headers": {
              "X-Request-Id": {
                "description": "Unique per request; also requestId in an error body.",
                "schema": {
                  "type": "string",
                  "format": "uuid"
                }
              }
            },
            "description": "INTERNAL_ERROR: retry, and quote requestId to support if it keeps failing.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicError"
                }
              }
            }
          }
        },
        "tags": [
          "Public API"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/api/v1/public/reviews/{id}": {
      "get": {
        "operationId": "PublicReviewsController_getOne",
        "summary": "One review",
        "description": "Scope reviews:read.",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "description": "Review id",
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "headers": {
              "X-Request-Id": {
                "description": "Unique per request; also requestId in an error body.",
                "schema": {
                  "type": "string",
                  "format": "uuid"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Requests allowed per minute per key (60). Absent while the limiter is unavailable.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requests left in the current minute. Absent while the limiter is unavailable.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix time (seconds) when the current minute ends. Absent while the limiter is unavailable.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicReview"
                }
              }
            }
          },
          "400": {
            "headers": {
              "X-Request-Id": {
                "description": "Unique per request; also requestId in an error body.",
                "schema": {
                  "type": "string",
                  "format": "uuid"
                }
              }
            },
            "description": "VALIDATION_FAILED: the id is not a uuid.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicError"
                }
              }
            }
          },
          "401": {
            "headers": {
              "X-Request-Id": {
                "description": "Unique per request; also requestId in an error body.",
                "schema": {
                  "type": "string",
                  "format": "uuid"
                }
              }
            },
            "description": "MISSING_KEY, INVALID_KEY, KEY_REVOKED, KEY_EXPIRED.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicError"
                }
              }
            }
          },
          "403": {
            "headers": {
              "X-Request-Id": {
                "description": "Unique per request; also requestId in an error body.",
                "schema": {
                  "type": "string",
                  "format": "uuid"
                }
              }
            },
            "description": "PLAN_REQUIRED (with requiredTier): the API is part of Pro and above. INSUFFICIENT_SCOPE: the key lacks the scope of this route. FORBIDDEN: any other refusal of access.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicError"
                }
              }
            }
          },
          "404": {
            "headers": {
              "X-Request-Id": {
                "description": "Unique per request; also requestId in an error body.",
                "schema": {
                  "type": "string",
                  "format": "uuid"
                }
              }
            },
            "description": "NOT_FOUND: no such review in this organization.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicError"
                }
              }
            }
          },
          "408": {
            "headers": {
              "X-Request-Id": {
                "description": "Unique per request; also requestId in an error body.",
                "schema": {
                  "type": "string",
                  "format": "uuid"
                }
              }
            },
            "description": "TIMEOUT: we did not answer in time, so the result is unknown. Retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicError"
                }
              }
            }
          },
          "429": {
            "headers": {
              "X-Request-Id": {
                "description": "Unique per request; also requestId in an error body.",
                "schema": {
                  "type": "string",
                  "format": "uuid"
                }
              },
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "description": "RATE_LIMITED: up to 60 requests a minute per key, or too many failed authentications from one IP.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicError"
                }
              }
            }
          },
          "500": {
            "headers": {
              "X-Request-Id": {
                "description": "Unique per request; also requestId in an error body.",
                "schema": {
                  "type": "string",
                  "format": "uuid"
                }
              }
            },
            "description": "INTERNAL_ERROR: retry, and quote requestId to support if it keeps failing.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicError"
                }
              }
            }
          }
        },
        "tags": [
          "Public API"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/api/v1/public/reviews/{id}/reply": {
      "post": {
        "operationId": "PublicReviewsController_reply",
        "summary": "Publish a reply on the platform",
        "description": "Scope reviews:reply. The text is published as sent. Editing a published reply is not available. Answers the review with its reply. Where the API publishes: Google; Facebook and Instagram pages already connected in RevioReputation. LINKEDIN (a person publishes every reply there) and the read-only platforms (TRIPADVISOR, TRUSTPILOT, YELP, BOOKING, AIRBNB) answer 409 MANUAL_POST_REQUIRED with platformUrl, where you post it yourself. Other platforms answer 400 PLATFORM_REPLY_UNSUPPORTED.",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "description": "Review id",
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "name": "Idempotency-Key",
            "required": false,
            "in": "header",
            "description": "1 to 100 characters, remembered 24 hours per key: a retry with the same key and body gets the first answer and never publishes twice.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PublicReplyRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "headers": {
              "X-Request-Id": {
                "description": "Unique per request; also requestId in an error body.",
                "schema": {
                  "type": "string",
                  "format": "uuid"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Requests allowed per minute per key (60). Absent while the limiter is unavailable.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requests left in the current minute. Absent while the limiter is unavailable.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix time (seconds) when the current minute ends. Absent while the limiter is unavailable.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "description": "Published. The review, with its reply.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicReview"
                }
              }
            }
          },
          "400": {
            "headers": {
              "X-Request-Id": {
                "description": "Unique per request; also requestId in an error body.",
                "schema": {
                  "type": "string",
                  "format": "uuid"
                }
              }
            },
            "description": "VALIDATION_FAILED: empty or too long text, or a bad Idempotency-Key. INVALID_JSON: the body is not valid JSON. INTEGRATION_REQUIRED: the location is not connected to the platform. PLATFORM_REPLY_UNSUPPORTED: replying to this platform is not available.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicError"
                }
              }
            }
          },
          "401": {
            "headers": {
              "X-Request-Id": {
                "description": "Unique per request; also requestId in an error body.",
                "schema": {
                  "type": "string",
                  "format": "uuid"
                }
              }
            },
            "description": "MISSING_KEY, INVALID_KEY, KEY_REVOKED, KEY_EXPIRED.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicError"
                }
              }
            }
          },
          "403": {
            "headers": {
              "X-Request-Id": {
                "description": "Unique per request; also requestId in an error body.",
                "schema": {
                  "type": "string",
                  "format": "uuid"
                }
              }
            },
            "description": "PLAN_REQUIRED (with requiredTier): the API is part of Pro and above. INSUFFICIENT_SCOPE: the key lacks the scope of this route. FORBIDDEN: any other refusal of access.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicError"
                }
              }
            }
          },
          "404": {
            "headers": {
              "X-Request-Id": {
                "description": "Unique per request; also requestId in an error body.",
                "schema": {
                  "type": "string",
                  "format": "uuid"
                }
              }
            },
            "description": "NOT_FOUND: no such review in this organization.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicError"
                }
              }
            }
          },
          "408": {
            "headers": {
              "X-Request-Id": {
                "description": "Unique per request; also requestId in an error body.",
                "schema": {
                  "type": "string",
                  "format": "uuid"
                }
              }
            },
            "description": "TIMEOUT: the platform took too long, so the result is unknown and the reply may still be published. Retry with the same Idempotency-Key: you get the answer of the first request, never a second post.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicError"
                }
              }
            }
          },
          "409": {
            "headers": {
              "X-Request-Id": {
                "description": "Unique per request; also requestId in an error body.",
                "schema": {
                  "type": "string",
                  "format": "uuid"
                }
              }
            },
            "description": "ALREADY_REPLIED: the review already has a published reply. MANUAL_POST_REQUIRED (with platformUrl): the API does not publish on this platform, post it yourself. REQUEST_IN_PROGRESS: the same reply is being published, retry in a few seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicError"
                }
              }
            }
          },
          "413": {
            "headers": {
              "X-Request-Id": {
                "description": "Unique per request; also requestId in an error body.",
                "schema": {
                  "type": "string",
                  "format": "uuid"
                }
              }
            },
            "description": "PAYLOAD_TOO_LARGE: the body is over 100 kB.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicError"
                }
              }
            }
          },
          "422": {
            "headers": {
              "X-Request-Id": {
                "description": "Unique per request; also requestId in an error body.",
                "schema": {
                  "type": "string",
                  "format": "uuid"
                }
              }
            },
            "description": "IDEMPOTENCY_MISMATCH: this Idempotency-Key was used with a different request. PLATFORM_POST_FAILED: on Google the platform refused the reply and nothing was published. On Facebook and Instagram: The platform did not confirm the reply. It may already be visible there: check before posting again. A retry with the same Idempotency-Key returns this same answer.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicError"
                }
              }
            }
          },
          "429": {
            "headers": {
              "X-Request-Id": {
                "description": "Unique per request; also requestId in an error body.",
                "schema": {
                  "type": "string",
                  "format": "uuid"
                }
              },
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "description": "RATE_LIMITED: up to 60 requests a minute per key, or too many failed authentications from one IP.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicError"
                }
              }
            }
          },
          "500": {
            "headers": {
              "X-Request-Id": {
                "description": "Unique per request; also requestId in an error body.",
                "schema": {
                  "type": "string",
                  "format": "uuid"
                }
              }
            },
            "description": "INTERNAL_ERROR: retry, and quote requestId to support if it keeps failing.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicError"
                }
              }
            }
          },
          "503": {
            "headers": {
              "X-Request-Id": {
                "description": "Unique per request; also requestId in an error body.",
                "schema": {
                  "type": "string",
                  "format": "uuid"
                }
              },
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "description": "IDEMPOTENCY_UNAVAILABLE: requests with an Idempotency-Key are briefly unavailable, nothing was published.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicError"
                }
              }
            }
          }
        },
        "tags": [
          "Public API"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/api/v1/public/webhooks": {
      "get": {
        "operationId": "PublicWebhooksController_list",
        "summary": "Webhook subscriptions made with this key",
        "description": "Scope webhooks:manage. Subscriptions made in RevioReputation or with other keys are not listed.",
        "parameters": [],
        "responses": {
          "200": {
            "headers": {
              "X-Request-Id": {
                "description": "Unique per request; also requestId in an error body.",
                "schema": {
                  "type": "string",
                  "format": "uuid"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Requests allowed per minute per key (60). Absent while the limiter is unavailable.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requests left in the current minute. Absent while the limiter is unavailable.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix time (seconds) when the current minute ends. Absent while the limiter is unavailable.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicWebhookList"
                }
              }
            }
          },
          "401": {
            "headers": {
              "X-Request-Id": {
                "description": "Unique per request; also requestId in an error body.",
                "schema": {
                  "type": "string",
                  "format": "uuid"
                }
              }
            },
            "description": "MISSING_KEY, INVALID_KEY, KEY_REVOKED, KEY_EXPIRED.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicError"
                }
              }
            }
          },
          "403": {
            "headers": {
              "X-Request-Id": {
                "description": "Unique per request; also requestId in an error body.",
                "schema": {
                  "type": "string",
                  "format": "uuid"
                }
              }
            },
            "description": "PLAN_REQUIRED (with requiredTier): the API is part of Pro and above. INSUFFICIENT_SCOPE: the key lacks the scope of this route. FORBIDDEN: any other refusal of access.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicError"
                }
              }
            }
          },
          "408": {
            "headers": {
              "X-Request-Id": {
                "description": "Unique per request; also requestId in an error body.",
                "schema": {
                  "type": "string",
                  "format": "uuid"
                }
              }
            },
            "description": "TIMEOUT: we did not answer in time, so the result is unknown. Retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicError"
                }
              }
            }
          },
          "429": {
            "headers": {
              "X-Request-Id": {
                "description": "Unique per request; also requestId in an error body.",
                "schema": {
                  "type": "string",
                  "format": "uuid"
                }
              },
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "description": "RATE_LIMITED: up to 60 requests a minute per key, or too many failed authentications from one IP.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicError"
                }
              }
            }
          },
          "500": {
            "headers": {
              "X-Request-Id": {
                "description": "Unique per request; also requestId in an error body.",
                "schema": {
                  "type": "string",
                  "format": "uuid"
                }
              }
            },
            "description": "INTERNAL_ERROR: retry, and quote requestId to support if it keeps failing.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicError"
                }
              }
            }
          }
        },
        "tags": [
          "Public API"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      },
      "post": {
        "operationId": "PublicWebhooksController_create",
        "summary": "Subscribe an address to events",
        "description": "Scope webhooks:manage (REST hooks). The subscription belongs to this key and is removed when the key is revoked. Subscribing the same address again with the same key reactivates it with a new secret.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PublicWebhookSubscribeRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "headers": {
              "X-Request-Id": {
                "description": "Unique per request; also requestId in an error body.",
                "schema": {
                  "type": "string",
                  "format": "uuid"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Requests allowed per minute per key (60). Absent while the limiter is unavailable.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requests left in the current minute. Absent while the limiter is unavailable.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix time (seconds) when the current minute ends. Absent while the limiter is unavailable.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "description": "Subscribed. The signing secret is returned only here.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicWebhookCreated"
                }
              }
            }
          },
          "400": {
            "headers": {
              "X-Request-Id": {
                "description": "Unique per request; also requestId in an error body.",
                "schema": {
                  "type": "string",
                  "format": "uuid"
                }
              }
            },
            "description": "VALIDATION_FAILED: missing or unknown fields. INVALID_JSON: the body is not valid JSON. INVALID_URL: not a public https address on an allowed port.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicError"
                }
              }
            }
          },
          "401": {
            "headers": {
              "X-Request-Id": {
                "description": "Unique per request; also requestId in an error body.",
                "schema": {
                  "type": "string",
                  "format": "uuid"
                }
              }
            },
            "description": "MISSING_KEY, INVALID_KEY, KEY_REVOKED, KEY_EXPIRED.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicError"
                }
              }
            }
          },
          "403": {
            "headers": {
              "X-Request-Id": {
                "description": "Unique per request; also requestId in an error body.",
                "schema": {
                  "type": "string",
                  "format": "uuid"
                }
              }
            },
            "description": "PLAN_REQUIRED (with requiredTier): the API is part of Pro and above. INSUFFICIENT_SCOPE: the key lacks the scope of this route. FORBIDDEN: any other refusal of access.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicError"
                }
              }
            }
          },
          "408": {
            "headers": {
              "X-Request-Id": {
                "description": "Unique per request; also requestId in an error body.",
                "schema": {
                  "type": "string",
                  "format": "uuid"
                }
              }
            },
            "description": "TIMEOUT: we did not answer in time, so the result is unknown. Retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicError"
                }
              }
            }
          },
          "409": {
            "headers": {
              "X-Request-Id": {
                "description": "Unique per request; also requestId in an error body.",
                "schema": {
                  "type": "string",
                  "format": "uuid"
                }
              }
            },
            "description": "DUPLICATE_URL: the address is already subscribed in RevioReputation or by another key. TOO_MANY_ENDPOINTS: the organization has 10 addresses.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicError"
                }
              }
            }
          },
          "413": {
            "headers": {
              "X-Request-Id": {
                "description": "Unique per request; also requestId in an error body.",
                "schema": {
                  "type": "string",
                  "format": "uuid"
                }
              }
            },
            "description": "PAYLOAD_TOO_LARGE: the body is over 100 kB.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicError"
                }
              }
            }
          },
          "429": {
            "headers": {
              "X-Request-Id": {
                "description": "Unique per request; also requestId in an error body.",
                "schema": {
                  "type": "string",
                  "format": "uuid"
                }
              },
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "description": "RATE_LIMITED: up to 60 requests a minute per key, or too many failed authentications from one IP.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicError"
                }
              }
            }
          },
          "500": {
            "headers": {
              "X-Request-Id": {
                "description": "Unique per request; also requestId in an error body.",
                "schema": {
                  "type": "string",
                  "format": "uuid"
                }
              }
            },
            "description": "INTERNAL_ERROR: retry, and quote requestId to support if it keeps failing.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicError"
                }
              }
            }
          }
        },
        "tags": [
          "Public API"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/api/v1/public/webhooks/{id}": {
      "delete": {
        "operationId": "PublicWebhooksController_remove",
        "summary": "Unsubscribe",
        "description": "Scope webhooks:manage. Only subscriptions made with this key.",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "description": "Subscription id",
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "headers": {
              "X-Request-Id": {
                "description": "Unique per request; also requestId in an error body.",
                "schema": {
                  "type": "string",
                  "format": "uuid"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Requests allowed per minute per key (60). Absent while the limiter is unavailable.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requests left in the current minute. Absent while the limiter is unavailable.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix time (seconds) when the current minute ends. Absent while the limiter is unavailable.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicWebhookDeleted"
                }
              }
            }
          },
          "400": {
            "headers": {
              "X-Request-Id": {
                "description": "Unique per request; also requestId in an error body.",
                "schema": {
                  "type": "string",
                  "format": "uuid"
                }
              }
            },
            "description": "VALIDATION_FAILED: the id is not a uuid.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicError"
                }
              }
            }
          },
          "401": {
            "headers": {
              "X-Request-Id": {
                "description": "Unique per request; also requestId in an error body.",
                "schema": {
                  "type": "string",
                  "format": "uuid"
                }
              }
            },
            "description": "MISSING_KEY, INVALID_KEY, KEY_REVOKED, KEY_EXPIRED.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicError"
                }
              }
            }
          },
          "403": {
            "headers": {
              "X-Request-Id": {
                "description": "Unique per request; also requestId in an error body.",
                "schema": {
                  "type": "string",
                  "format": "uuid"
                }
              }
            },
            "description": "PLAN_REQUIRED (with requiredTier): the API is part of Pro and above. INSUFFICIENT_SCOPE: the key lacks the scope of this route. FORBIDDEN: any other refusal of access.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicError"
                }
              }
            }
          },
          "404": {
            "headers": {
              "X-Request-Id": {
                "description": "Unique per request; also requestId in an error body.",
                "schema": {
                  "type": "string",
                  "format": "uuid"
                }
              }
            },
            "description": "NOT_FOUND: no such subscription made with this key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicError"
                }
              }
            }
          },
          "408": {
            "headers": {
              "X-Request-Id": {
                "description": "Unique per request; also requestId in an error body.",
                "schema": {
                  "type": "string",
                  "format": "uuid"
                }
              }
            },
            "description": "TIMEOUT: we did not answer in time, so the result is unknown. Retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicError"
                }
              }
            }
          },
          "429": {
            "headers": {
              "X-Request-Id": {
                "description": "Unique per request; also requestId in an error body.",
                "schema": {
                  "type": "string",
                  "format": "uuid"
                }
              },
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "description": "RATE_LIMITED: up to 60 requests a minute per key, or too many failed authentications from one IP.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicError"
                }
              }
            }
          },
          "500": {
            "headers": {
              "X-Request-Id": {
                "description": "Unique per request; also requestId in an error body.",
                "schema": {
                  "type": "string",
                  "format": "uuid"
                }
              }
            },
            "description": "INTERNAL_ERROR: retry, and quote requestId to support if it keeps failing.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicError"
                }
              }
            }
          }
        },
        "tags": [
          "Public API"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/api/v1/public/webhooks/{id}/test": {
      "post": {
        "operationId": "PublicWebhooksController_test",
        "summary": "Send a test event (ping) now",
        "description": "Scope webhooks:manage. Whatever the subscription status; not retried. One test per address every 5 seconds, 20 a minute per organization.",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "description": "Subscription id",
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "headers": {
              "X-Request-Id": {
                "description": "Unique per request; also requestId in an error body.",
                "schema": {
                  "type": "string",
                  "format": "uuid"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Requests allowed per minute per key (60). Absent while the limiter is unavailable.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requests left in the current minute. Absent while the limiter is unavailable.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix time (seconds) when the current minute ends. Absent while the limiter is unavailable.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "description": "The outcome of the delivery (a failed delivery is still 200).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicWebhookTestResult"
                }
              }
            }
          },
          "400": {
            "headers": {
              "X-Request-Id": {
                "description": "Unique per request; also requestId in an error body.",
                "schema": {
                  "type": "string",
                  "format": "uuid"
                }
              }
            },
            "description": "VALIDATION_FAILED: the id is not a uuid.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicError"
                }
              }
            }
          },
          "401": {
            "headers": {
              "X-Request-Id": {
                "description": "Unique per request; also requestId in an error body.",
                "schema": {
                  "type": "string",
                  "format": "uuid"
                }
              }
            },
            "description": "MISSING_KEY, INVALID_KEY, KEY_REVOKED, KEY_EXPIRED.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicError"
                }
              }
            }
          },
          "403": {
            "headers": {
              "X-Request-Id": {
                "description": "Unique per request; also requestId in an error body.",
                "schema": {
                  "type": "string",
                  "format": "uuid"
                }
              }
            },
            "description": "PLAN_REQUIRED (with requiredTier): the API is part of Pro and above. INSUFFICIENT_SCOPE: the key lacks the scope of this route. FORBIDDEN: any other refusal of access.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicError"
                }
              }
            }
          },
          "404": {
            "headers": {
              "X-Request-Id": {
                "description": "Unique per request; also requestId in an error body.",
                "schema": {
                  "type": "string",
                  "format": "uuid"
                }
              }
            },
            "description": "NOT_FOUND: no such subscription made with this key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicError"
                }
              }
            }
          },
          "408": {
            "headers": {
              "X-Request-Id": {
                "description": "Unique per request; also requestId in an error body.",
                "schema": {
                  "type": "string",
                  "format": "uuid"
                }
              }
            },
            "description": "TIMEOUT: we did not answer in time, so the result is unknown. Retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicError"
                }
              }
            }
          },
          "429": {
            "headers": {
              "X-Request-Id": {
                "description": "Unique per request; also requestId in an error body.",
                "schema": {
                  "type": "string",
                  "format": "uuid"
                }
              },
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "description": "RATE_LIMITED (with retryAfterSeconds): wait before the next test.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicError"
                }
              }
            }
          },
          "500": {
            "headers": {
              "X-Request-Id": {
                "description": "Unique per request; also requestId in an error body.",
                "schema": {
                  "type": "string",
                  "format": "uuid"
                }
              }
            },
            "description": "INTERNAL_ERROR: retry, and quote requestId to support if it keeps failing.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicError"
                }
              }
            }
          }
        },
        "tags": [
          "Public API"
        ],
        "security": [
          {
            "bearer": []
          }
        ]
      }
    }
  },
  "info": {
    "title": "RevioReputation Public API",
    "description": "Read reviews and locations, publish replies, subscribe to webhooks. Part of the Pro plan and above.\n\nAuthentication: `Authorization: Bearer rk_live_...`, a key created in RevioReputation > Integrations > Developers. A key has scopes (reviews:read, reviews:reply, locations:read, webhooks:manage), chosen at creation. Server-to-server only: never put an API key in a browser or a mobile app.\n\nRate limit: 60 requests a minute per key (X-RateLimit-* headers; 429 with Retry-After).\n\nErrors: `{\"error\":{\"code\",\"message\",\"requestId\"}}`, the same requestId as the X-Request-Id header. Codes: MISSING_KEY, INVALID_KEY, KEY_REVOKED, KEY_EXPIRED, PLAN_REQUIRED, INSUFFICIENT_SCOPE, FORBIDDEN, TIMEOUT, RATE_LIMITED, VALIDATION_FAILED, INVALID_JSON, PAYLOAD_TOO_LARGE, INVALID_CURSOR, INVALID_URL, NOT_FOUND, ALREADY_REPLIED, MANUAL_POST_REQUIRED, INTEGRATION_REQUIRED, PLATFORM_POST_FAILED, PLATFORM_REPLY_UNSUPPORTED, IDEMPOTENCY_MISMATCH, REQUEST_IN_PROGRESS, IDEMPOTENCY_UNAVAILABLE, DUPLICATE_URL, TOO_MANY_ENDPOINTS, CONFLICT, UNPROCESSABLE, ERROR, INTERNAL_ERROR. A body that is not valid JSON is 400 INVALID_JSON, a body over 100 kB is 413 PAYLOAD_TOO_LARGE, an unknown path is 404 NOT_FOUND.\n\nWebhooks: we POST the event as JSON (see x-webhooks: review.created, review.replied, review.negative, ping). Verify Revio-Signature: t=<unix seconds>,v1=<hex HMAC-SHA256(secret, t + \".\" + raw body)>, and refuse a t older than 5 minutes. Answer 2xx; other answers are retried, and 410 Gone switches the address off.\n\nDocs: https://revioreputation.com/developers",
    "version": "1.0.0",
    "contact": {}
  },
  "tags": [],
  "servers": [
    {
      "url": "https://revioreputation.com"
    }
  ],
  "components": {
    "securitySchemes": {
      "bearer": {
        "scheme": "bearer",
        "bearerFormat": "rk_live_...",
        "type": "http"
      }
    },
    "schemas": {
      "PublicErrorBody": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "example": "INSUFFICIENT_SCOPE",
            "description": "Stable code, see the list in the API description."
          },
          "message": {
            "type": "string",
            "description": "English, for a person. May change; branch on code."
          },
          "requestId": {
            "type": "string",
            "format": "uuid",
            "description": "Same as the X-Request-Id header. Quote it to support."
          },
          "requiredTier": {
            "type": "string",
            "enum": [
              "FREE",
              "STARTER",
              "PRO",
              "ENTERPRISE",
              "AGENCY",
              "WIDGET_PRO"
            ],
            "description": "With PLAN_REQUIRED: the plan that includes the API."
          },
          "platformUrl": {
            "type": "string",
            "format": "uri",
            "description": "With MANUAL_POST_REQUIRED: where to post the reply yourself."
          },
          "retryAfterSeconds": {
            "type": "integer",
            "description": "With some RATE_LIMITED answers: seconds to wait (also in Retry-After)."
          }
        },
        "required": [
          "code",
          "message",
          "requestId"
        ]
      },
      "PublicError": {
        "type": "object",
        "properties": {
          "error": {
            "$ref": "#/components/schemas/PublicErrorBody"
          }
        },
        "required": [
          "error"
        ]
      },
      "PublicMeOrganization": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": "string"
          }
        },
        "required": [
          "id",
          "name"
        ]
      },
      "PublicKey": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": "string"
          },
          "displayPrefix": {
            "type": "string",
            "example": "rk_live_ab12",
            "description": "The first characters of the key, as shown in RevioReputation."
          },
          "scopes": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "reviews:read",
                "reviews:reply",
                "locations:read",
                "webhooks:manage"
              ]
            }
          },
          "expiresAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "null: the key does not expire."
          }
        },
        "required": [
          "id",
          "name",
          "displayPrefix",
          "scopes",
          "expiresAt"
        ]
      },
      "PublicMe": {
        "type": "object",
        "properties": {
          "organization": {
            "$ref": "#/components/schemas/PublicMeOrganization"
          },
          "key": {
            "$ref": "#/components/schemas/PublicKey"
          },
          "plan": {
            "type": "string",
            "enum": [
              "FREE",
              "STARTER",
              "PRO",
              "ENTERPRISE",
              "AGENCY",
              "WIDGET_PRO"
            ],
            "description": "The plan of the organization owner."
          }
        },
        "required": [
          "organization",
          "key",
          "plan"
        ]
      },
      "PublicLocation": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": "string"
          },
          "city": {
            "type": "string"
          },
          "country": {
            "type": "string"
          },
          "platforms": {
            "type": "array",
            "description": "Platforms connected to this location.",
            "items": {
              "type": "string",
              "enum": [
                "GOOGLE",
                "FACEBOOK",
                "INSTAGRAM",
                "LINKEDIN",
                "TIKTOK",
                "YELP",
                "TRUSTPILOT",
                "TRIPADVISOR",
                "BOOKING",
                "AIRBNB",
                "G2",
                "CAPTERRA",
                "SOFTWARE_ADVICE",
                "FOURSQUARE",
                "MERCADO_LIBRE",
                "LOCAL_GUIDES"
              ]
            }
          }
        },
        "required": [
          "id",
          "name",
          "city",
          "country",
          "platforms"
        ]
      },
      "PublicLocationList": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicLocation"
            }
          }
        },
        "required": [
          "data"
        ]
      },
      "PublicReviewAuthor": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          }
        },
        "required": [
          "name"
        ]
      },
      "PublicReviewReply": {
        "type": "object",
        "properties": {
          "text": {
            "type": "string",
            "description": "The reply as published on the platform."
          },
          "publishedAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "source": {
            "type": "string",
            "enum": [
              "revio",
              "autopilot",
              "api",
              "platform"
            ],
            "description": "revio: a person in RevioReputation; autopilot: our AI on autopilot; api: through this API; platform: answered on the platform itself."
          }
        },
        "required": [
          "text",
          "publishedAt",
          "source"
        ]
      },
      "PublicReview": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "locationId": {
            "type": "string",
            "format": "uuid"
          },
          "platform": {
            "type": "string",
            "enum": [
              "GOOGLE",
              "FACEBOOK",
              "INSTAGRAM",
              "LINKEDIN",
              "TIKTOK",
              "YELP",
              "TRUSTPILOT",
              "TRIPADVISOR",
              "BOOKING",
              "AIRBNB",
              "G2",
              "CAPTERRA",
              "SOFTWARE_ADVICE",
              "FOURSQUARE",
              "MERCADO_LIBRE",
              "LOCAL_GUIDES"
            ]
          },
          "contentType": {
            "type": "string",
            "enum": [
              "REVIEW",
              "RECOMMENDATION",
              "COMMENT",
              "MENTION",
              "TIP"
            ],
            "description": "REVIEW and RECOMMENDATION carry stars; COMMENT, MENTION and TIP do not."
          },
          "rating": {
            "type": "integer",
            "nullable": true,
            "description": "Stars, 1 to 5. null for content without stars (comments, mentions, tips)."
          },
          "text": {
            "type": "string",
            "nullable": true,
            "description": "null when the customer left stars without words."
          },
          "language": {
            "type": "string",
            "nullable": true,
            "description": "Language code of the review text, when known."
          },
          "author": {
            "$ref": "#/components/schemas/PublicReviewAuthor"
          },
          "reviewedAt": {
            "type": "string",
            "format": "date-time",
            "description": "When the customer wrote it."
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "description": "When RevioReputation received it. The list is ordered by this, newest first."
          },
          "status": {
            "type": "string",
            "enum": [
              "new",
              "pending",
              "replied",
              "ignored",
              "archived"
            ]
          },
          "reply": {
            "nullable": true,
            "description": "The published reply; null until one is published.",
            "allOf": [
              {
                "$ref": "#/components/schemas/PublicReviewReply"
              }
            ]
          },
          "url": {
            "type": "string",
            "format": "uri",
            "description": "Where a person can read the review or the business page. Absent when unknown."
          }
        },
        "required": [
          "id",
          "locationId",
          "platform",
          "contentType",
          "rating",
          "text",
          "language",
          "author",
          "reviewedAt",
          "createdAt",
          "status",
          "reply"
        ]
      },
      "PublicReviewList": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicReview"
            }
          },
          "nextCursor": {
            "type": "string",
            "nullable": true,
            "description": "Pass as `cursor` to get the next page; null on the last page."
          }
        },
        "required": [
          "data",
          "nextCursor"
        ]
      },
      "PublicReplyRequest": {
        "type": "object",
        "properties": {
          "text": {
            "type": "string",
            "minLength": 1,
            "maxLength": 4096,
            "description": "Trimmed; published as sent."
          }
        },
        "required": [
          "text"
        ]
      },
      "PublicWebhook": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "url": {
            "type": "string",
            "format": "uri"
          },
          "description": {
            "type": "string",
            "nullable": true
          },
          "events": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "review.created",
                "review.replied",
                "review.negative"
              ]
            }
          },
          "source": {
            "type": "string",
            "enum": [
              "cabinet",
              "api"
            ],
            "description": "api for subscriptions made with a key."
          },
          "status": {
            "type": "string",
            "enum": [
              "ACTIVE",
              "PAUSED",
              "DISABLED"
            ]
          },
          "disabledReason": {
            "type": "string",
            "enum": [
              "failures",
              "gone",
              "plan",
              null
            ],
            "nullable": true,
            "description": "Why it is DISABLED: failures in a row, the receiver answered 410, the plan lost the API. null otherwise."
          },
          "consecutiveFailures": {
            "type": "integer"
          },
          "lastSuccessAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "lastFailureAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "lastError": {
            "type": "string",
            "nullable": true
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        },
        "required": [
          "id",
          "url",
          "description",
          "events",
          "source",
          "status",
          "disabledReason",
          "consecutiveFailures",
          "lastSuccessAt",
          "lastFailureAt",
          "lastError",
          "createdAt"
        ]
      },
      "PublicWebhookList": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicWebhook"
            }
          }
        },
        "required": [
          "data"
        ]
      },
      "PublicWebhookSubscribeRequest": {
        "type": "object",
        "properties": {
          "url": {
            "type": "string",
            "format": "uri",
            "maxLength": 2048,
            "description": "A public https address."
          },
          "events": {
            "type": "array",
            "minItems": 1,
            "uniqueItems": true,
            "items": {
              "type": "string",
              "enum": [
                "review.created",
                "review.replied",
                "review.negative"
              ]
            }
          },
          "description": {
            "type": "string",
            "maxLength": 200
          }
        },
        "required": [
          "url",
          "events"
        ]
      },
      "PublicWebhookCreated": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "url": {
            "type": "string",
            "format": "uri"
          },
          "description": {
            "type": "string",
            "nullable": true
          },
          "events": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "review.created",
                "review.replied",
                "review.negative"
              ]
            }
          },
          "source": {
            "type": "string",
            "enum": [
              "cabinet",
              "api"
            ],
            "description": "api for subscriptions made with a key."
          },
          "status": {
            "type": "string",
            "enum": [
              "ACTIVE",
              "PAUSED",
              "DISABLED"
            ]
          },
          "disabledReason": {
            "type": "string",
            "enum": [
              "failures",
              "gone",
              "plan",
              null
            ],
            "nullable": true,
            "description": "Why it is DISABLED: failures in a row, the receiver answered 410, the plan lost the API. null otherwise."
          },
          "consecutiveFailures": {
            "type": "integer"
          },
          "lastSuccessAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "lastFailureAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "lastError": {
            "type": "string",
            "nullable": true
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "secret": {
            "type": "string",
            "example": "whsec_...",
            "description": "Signing secret of the Revio-Signature header. Returned only here: store it."
          }
        },
        "required": [
          "id",
          "url",
          "description",
          "events",
          "source",
          "status",
          "disabledReason",
          "consecutiveFailures",
          "lastSuccessAt",
          "lastFailureAt",
          "lastError",
          "createdAt",
          "secret"
        ]
      },
      "PublicWebhookDeleted": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "deleted": {
            "type": "boolean",
            "description": "Always true."
          }
        },
        "required": [
          "id",
          "deleted"
        ]
      },
      "PublicWebhookTestResult": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean",
            "description": "true when the address answered 2xx."
          },
          "statusCode": {
            "type": "integer",
            "nullable": true,
            "description": "HTTP status of the answer; null when there was none (timeout, refused)."
          },
          "durationMs": {
            "type": "integer"
          },
          "error": {
            "type": "string",
            "nullable": true,
            "description": "Short reason of a failure; never the body of your answer."
          }
        },
        "required": [
          "ok",
          "statusCode",
          "durationMs",
          "error"
        ]
      },
      "WebhookEventLocation": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": "string"
          }
        },
        "required": [
          "id",
          "name"
        ]
      },
      "WebhookReviewEventData": {
        "type": "object",
        "properties": {
          "review": {
            "description": "The review as GET /api/v1/public/reviews/{id} returns it, when the event happened.",
            "allOf": [
              {
                "$ref": "#/components/schemas/PublicReview"
              }
            ]
          },
          "location": {
            "$ref": "#/components/schemas/WebhookEventLocation"
          }
        },
        "required": [
          "review",
          "location"
        ]
      },
      "WebhookReviewEvent": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "evt_0123456789ABCDEFabcdefgh",
            "description": "Unique per event: deduplicate retries by it."
          },
          "apiVersion": {
            "type": "string",
            "enum": [
              "2026-11-01"
            ],
            "description": "A breaking change of the payload gets a new date."
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "organizationId": {
            "type": "string",
            "format": "uuid"
          },
          "type": {
            "type": "string",
            "enum": [
              "review.created",
              "review.replied",
              "review.negative"
            ]
          },
          "data": {
            "$ref": "#/components/schemas/WebhookReviewEventData"
          }
        },
        "required": [
          "id",
          "apiVersion",
          "createdAt",
          "organizationId",
          "type",
          "data"
        ]
      },
      "WebhookPingData": {
        "type": "object",
        "properties": {
          "message": {
            "type": "string",
            "example": "Test event from RevioReputation"
          }
        },
        "required": [
          "message"
        ]
      },
      "WebhookPingEvent": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "evt_0123456789ABCDEFabcdefgh",
            "description": "Unique per event: deduplicate retries by it."
          },
          "apiVersion": {
            "type": "string",
            "enum": [
              "2026-11-01"
            ],
            "description": "A breaking change of the payload gets a new date."
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "organizationId": {
            "type": "string",
            "format": "uuid"
          },
          "type": {
            "type": "string",
            "enum": [
              "ping"
            ]
          },
          "data": {
            "$ref": "#/components/schemas/WebhookPingData"
          }
        },
        "required": [
          "id",
          "apiVersion",
          "createdAt",
          "organizationId",
          "type",
          "data"
        ]
      }
    }
  },
  "x-webhooks": {
    "review": {
      "post": {
        "summary": "A review event: review.created, review.replied, review.negative",
        "parameters": [
          {
            "name": "User-Agent",
            "in": "header",
            "required": true,
            "description": "Always this value.",
            "schema": {
              "type": "string",
              "enum": [
                "RevioReputation-Webhooks/1.0"
              ]
            }
          },
          {
            "name": "Revio-Event-Id",
            "in": "header",
            "required": true,
            "description": "Same as the id in the body.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Revio-Event-Type",
            "in": "header",
            "required": true,
            "description": "Same as the type in the body.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Revio-Delivery-Id",
            "in": "header",
            "required": true,
            "description": "One attempt chain of one event to one address.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Revio-Signature",
            "in": "header",
            "required": true,
            "description": "t=<unix seconds>,v1=<hex HMAC-SHA256(secret, t + \".\" + raw body)>. Recompute it over the raw bytes and refuse a t older than 5 minutes. Exactly one v1 signature; rotating the secret switches signing immediately.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookReviewEvent"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Any 2xx acknowledges the delivery."
          }
        }
      }
    },
    "ping": {
      "post": {
        "summary": "The test event, sent only by the test button and POST /webhooks/{id}/test",
        "parameters": [
          {
            "name": "User-Agent",
            "in": "header",
            "required": true,
            "description": "Always this value.",
            "schema": {
              "type": "string",
              "enum": [
                "RevioReputation-Webhooks/1.0"
              ]
            }
          },
          {
            "name": "Revio-Event-Id",
            "in": "header",
            "required": true,
            "description": "Same as the id in the body.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Revio-Event-Type",
            "in": "header",
            "required": true,
            "description": "Same as the type in the body.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Revio-Delivery-Id",
            "in": "header",
            "required": true,
            "description": "One attempt chain of one event to one address.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Revio-Signature",
            "in": "header",
            "required": true,
            "description": "t=<unix seconds>,v1=<hex HMAC-SHA256(secret, t + \".\" + raw body)>. Recompute it over the raw bytes and refuse a t older than 5 minutes. Exactly one v1 signature; rotating the secret switches signing immediately.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookPingEvent"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Any 2xx acknowledges the delivery."
          }
        }
      }
    }
  }
}
