{
  "openapi": "3.0.1",
  "info": {
    "title": "HRS Hotel Reviews Scraper",
    "description": "Extract HRS guest reviews and hotel ratings: comments, category scores, reviewer profiles, traveler segments, aggregated summaries, stars, address, GPS. Optional English translation + sentiment. Date/score filtering. Reputation monitoring, competitor benchmarking, travel analytics, AI workflows.",
    "version": "0.1",
    "x-build-id": "fTX0coKgllN97w6hM"
  },
  "servers": [
    {
      "url": "https://api.apify.com/v2"
    }
  ],
  "paths": {
    "/acts/korado_labs~hrs-reviews-scraper/run-sync-get-dataset-items": {
      "post": {
        "operationId": "run-sync-get-dataset-items-korado_labs-hrs-reviews-scraper",
        "x-openai-isConsequential": false,
        "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
        "tags": [
          "Run Actor"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/inputSchema"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Enter your Apify token here"
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/acts/korado_labs~hrs-reviews-scraper/runs": {
      "post": {
        "operationId": "runs-sync-korado_labs-hrs-reviews-scraper",
        "x-openai-isConsequential": false,
        "summary": "Executes an Actor and returns information about the initiated run in response.",
        "tags": [
          "Run Actor"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/inputSchema"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Enter your Apify token here"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/runsResponseSchema"
                }
              }
            }
          }
        }
      }
    },
    "/acts/korado_labs~hrs-reviews-scraper/run-sync": {
      "post": {
        "operationId": "run-sync-korado_labs-hrs-reviews-scraper",
        "x-openai-isConsequential": false,
        "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
        "tags": [
          "Run Actor"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/inputSchema"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Enter your Apify token here"
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "inputSchema": {
        "type": "object",
        "properties": {
          "startUrls": {
            "title": "HRS hotel URLs",
            "type": "array",
            "description": "Public HRS hotel detail pages. All three URL shapes work: /en/hotel/391864, /en/hotel/<slug>-391864 and /en/detail?hn=391864. Any of the seven HRS locales and both hrs.com and hrs.de are accepted. If you provide neither startUrls nor hotelIds, one demo hotel is scraped so the run returns something to look at.",
            "items": {
              "type": "object",
              "required": [
                "url"
              ],
              "properties": {
                "url": {
                  "type": "string",
                  "title": "URL of a web page",
                  "format": "uri"
                }
              }
            }
          },
          "hotelIds": {
            "title": "HRS hotel IDs",
            "type": "array",
            "description": "Numeric HRS hotel IDs, as an alternative or addition to startUrls. IDs are the stable join key: hotel names and URL slugs both change over time.",
            "default": [],
            "items": {
              "type": "string"
            }
          },
          "maxReviewsPerHotel": {
            "title": "Max reviews per hotel",
            "minimum": 0,
            "type": "integer",
            "description": "Cap on saved reviews per hotel. Leave at 0 to save every review HRS exposes. Reviews are sorted newest first, so a cap of 20 gives the 20 most recent.",
            "default": 0
          },
          "sortReviewsBy": {
            "title": "Sort reviews by",
            "enum": [
              "newest",
              "oldest",
              "highestScore",
              "lowestScore"
            ],
            "type": "string",
            "description": "Applied before the cap, so 'Newest first' with a cap of 20 returns the 20 most recent reviews.",
            "default": "newest"
          },
          "reviewsFrom": {
            "title": "Only reviews on or after this date",
            "type": "string",
            "description": "Inclusive ISO date (YYYY-MM-DD) for incremental runs. Leave empty to collect all available reviews."
          },
          "reviewsTo": {
            "title": "Only reviews on or before this date",
            "type": "string",
            "description": "Inclusive ISO date (YYYY-MM-DD). Combine with the field above to collect a fixed window."
          },
          "minScore": {
            "title": "Minimum review score",
            "minimum": 0,
            "maximum": 10,
            "type": "integer",
            "description": "Keep reviews scoring at least this much on HRS's 0-10 scale."
          },
          "maxScore": {
            "title": "Maximum review score",
            "minimum": 0,
            "maximum": 10,
            "type": "integer",
            "description": "Keep reviews scoring at most this much. Set this to 6 or lower to surface only complaints for alerting."
          },
          "travelerTypes": {
            "title": "Traveler segments",
            "type": "array",
            "description": "Keep only reviews from these HRS traveler segments. Leave empty for all segments.",
            "items": {
              "type": "string",
              "enum": [
                "BUSINESS",
                "PRIVATE",
                "YOUNG_COUPLE",
                "MATURE_COUPLE",
                "FAMILY_SMALL_CHILDREN",
                "FAMILY_OLDER_CHILDREN",
                "GROUP",
                "COMPANY",
                "CONFERENCE"
              ],
              "enumTitles": [
                "Business",
                "Private",
                "Young couple",
                "Mature couple",
                "Family, small children",
                "Family, older children",
                "Group",
                "Company",
                "Conference"
              ]
            },
            "default": []
          },
          "reviewLanguages": {
            "title": "Review languages",
            "type": "array",
            "description": "Keep only reviews written in these languages. Accepts two-letter codes (de) or the ISO-639-3 codes HRS reports (deu). Most HRS reviews are German.",
            "default": [],
            "items": {
              "type": "string"
            }
          },
          "onlyWithText": {
            "title": "Only reviews with written comments",
            "type": "boolean",
            "description": "Skip reviews that carry scores but no positive or negative comment text.",
            "default": false
          },
          "onlyRecommended": {
            "title": "Only reviews that recommend the hotel",
            "type": "boolean",
            "description": "Keep only reviews where the guest recommends the hotel.",
            "default": false
          },
          "translateToEnglish": {
            "title": "Translate reviews to English",
            "type": "boolean",
            "description": "HRS review text is written in the reviewer's own language and is predominantly German, even on English pages. Enable this to add English versions of every comment. Original text is always preserved in its own fields.",
            "default": false
          },
          "llmApiKey": {
            "title": "LLM API key",
            "type": "string",
            "description": "API key for translation. Works with OpenAI or any OpenAI-compatible provider. Leave empty to use the key configured on this Actor, if one is available."
          },
          "llmModel": {
            "title": "LLM model",
            "type": "string",
            "description": "Model used for translation.",
            "default": "gpt-4o-mini"
          },
          "llmBaseUrl": {
            "title": "LLM base URL",
            "type": "string",
            "description": "OpenAI-compatible base URL. Change this to use Azure OpenAI, OpenRouter, Together, or a local Ollama or vLLM server.",
            "default": "https://api.openai.com/v1"
          },
          "translationBatchSize": {
            "title": "Reviews per translation request",
            "minimum": 1,
            "maximum": 50,
            "type": "integer",
            "description": "How many reviews to translate per LLM call. Higher values cost less; lower values are more resilient to model errors.",
            "default": 20
          },
          "analyzeSentiment": {
            "title": "Analyse sentiment and themes",
            "type": "boolean",
            "description": "Label each review with a sentiment and tag which aspects the guest praised or complained about, then roll those up per hotel into top complaints and top praise. Uses the same LLM settings as translation.",
            "default": false
          },
          "topThemesPerHotel": {
            "title": "Themes per hotel summary",
            "minimum": 1,
            "maximum": 15,
            "type": "integer",
            "description": "How many entries to include in each hotel's top complaints and top praise lists.",
            "default": 5
          },
          "analysisBatchSize": {
            "title": "Reviews per analysis request",
            "minimum": 1,
            "maximum": 50,
            "type": "integer",
            "description": "How many reviews to analyse per LLM call.",
            "default": 15
          },
          "deduplicateAcrossRuns": {
            "title": "Only return reviews not seen in previous runs",
            "type": "boolean",
            "description": "Remembers which reviews earlier runs already saved and skips them. Turns a scheduled run into a monitoring job that only reports genuinely new reviews. Skipped reviews are also excluded from translation and analysis, so repeat runs cost far less.",
            "default": false
          },
          "dedupStoreName": {
            "title": "Deduplication state store",
            "type": "string",
            "description": "Named key-value store holding the seen-review state. Use different names to keep separate monitoring pipelines independent.",
            "default": "hrs-seen-reviews"
          },
          "anonymizeReviewers": {
            "title": "Anonymise reviewer names",
            "enum": [
              "none",
              "initials",
              "hash",
              "drop"
            ],
            "type": "string",
            "description": "HRS shows reviewer names as surname plus initial (for example 'Meyer F.'), which can identify an individual when combined with a hotel and stay date. Choose how to handle them. Reviews HRS already marks 'Anonymous' are never altered, and the deduplication key is preserved in every mode.",
            "default": "none"
          },
          "anonymizeSalt": {
            "title": "Pseudonym salt",
            "type": "string",
            "description": "Used only by the pseudonym mode. Supply a stable secret to keep the same reviewer mapped to the same pseudonym across runs. Leave empty and a random salt is generated per run, which prevents correlation but also means pseudonyms will not match between runs."
          },
          "redactNamesInText": {
            "title": "Remove reviewer names from review text",
            "type": "boolean",
            "description": "Some guests sign their reviews or name staff. This removes occurrences of the reviewer's own name from the comment text, including the translated versions.",
            "default": false
          },
          "includeHotelDetails": {
            "title": "Include hotel details",
            "type": "boolean",
            "description": "Fetch hotel name, star rating, city, country, timezone and GPS coordinates. Adds one batched request per 100 hotels. Also lets the Actor tell a mistyped hotel ID apart from a real hotel that simply has no reviews yet.",
            "default": true
          },
          "language": {
            "title": "Language",
            "enum": [
              "en",
              "de",
              "fr",
              "es",
              "it",
              "nl",
              "pl"
            ],
            "type": "string",
            "description": "Locale used for HRS responses. Note that guest review text is written in the reviewer's own language (predominantly German) regardless of this setting.",
            "default": "en"
          },
          "proxyConfiguration": {
            "title": "Proxy configuration",
            "type": "object",
            "description": "Optional. HRS serves these endpoints without a proxy for normal run sizes. Enable Apify Proxy only if a large batch starts getting refused.",
            "default": {
              "useApifyProxy": false
            }
          },
          "failOnNoResults": {
            "title": "Fail the run when nothing could be collected",
            "type": "boolean",
            "description": "On by default: a scheduled run that reports success while delivering no data is worse than one that alerts you. Turn it off if you would rather treat an HRS outage as an uneventful run, for example to keep a dashboard green. Individual hotel failures never fail the run either way - only a total loss does.",
            "default": true
          },
          "healthCheck": {
            "title": "Run a health check instead of scraping",
            "type": "boolean",
            "description": "Ignores all other input and instead verifies that the HRS API still returns the shape this Actor expects. Exits with a failure if anything structural changed. Schedule this and attach a webhook to run failure to be warned before your real runs start returning empty output.",
            "default": false
          }
        }
      },
      "runsResponseSchema": {
        "type": "object",
        "properties": {
          "data": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              },
              "actId": {
                "type": "string"
              },
              "userId": {
                "type": "string"
              },
              "startedAt": {
                "type": "string",
                "format": "date-time",
                "example": "2025-01-08T00:00:00.000Z"
              },
              "finishedAt": {
                "type": "string",
                "format": "date-time",
                "example": "2025-01-08T00:00:00.000Z"
              },
              "status": {
                "type": "string",
                "example": "READY"
              },
              "meta": {
                "type": "object",
                "properties": {
                  "origin": {
                    "type": "string",
                    "example": "API"
                  },
                  "userAgent": {
                    "type": "string"
                  }
                }
              },
              "stats": {
                "type": "object",
                "properties": {
                  "inputBodyLen": {
                    "type": "integer",
                    "example": 2000
                  },
                  "rebootCount": {
                    "type": "integer",
                    "example": 0
                  },
                  "restartCount": {
                    "type": "integer",
                    "example": 0
                  },
                  "resurrectCount": {
                    "type": "integer",
                    "example": 0
                  },
                  "computeUnits": {
                    "type": "integer",
                    "example": 0
                  }
                }
              },
              "options": {
                "type": "object",
                "properties": {
                  "build": {
                    "type": "string",
                    "example": "latest"
                  },
                  "timeoutSecs": {
                    "type": "integer",
                    "example": 300
                  },
                  "memoryMbytes": {
                    "type": "integer",
                    "example": 1024
                  },
                  "diskMbytes": {
                    "type": "integer",
                    "example": 2048
                  }
                }
              },
              "buildId": {
                "type": "string"
              },
              "defaultKeyValueStoreId": {
                "type": "string"
              },
              "defaultDatasetId": {
                "type": "string"
              },
              "defaultRequestQueueId": {
                "type": "string"
              },
              "buildNumber": {
                "type": "string",
                "example": "1.0.0"
              },
              "containerUrl": {
                "type": "string"
              },
              "usage": {
                "type": "object",
                "properties": {
                  "ACTOR_COMPUTE_UNITS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_WRITES": {
                    "type": "integer",
                    "example": 1
                  },
                  "KEY_VALUE_STORE_LISTS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_INTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_EXTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_SERPS": {
                    "type": "integer",
                    "example": 0
                  }
                }
              },
              "usageTotalUsd": {
                "type": "number",
                "example": 0.00005
              },
              "usageUsd": {
                "type": "object",
                "properties": {
                  "ACTOR_COMPUTE_UNITS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_WRITES": {
                    "type": "number",
                    "example": 0.00005
                  },
                  "KEY_VALUE_STORE_LISTS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_INTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_EXTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_SERPS": {
                    "type": "integer",
                    "example": 0
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}