{
  "openapi": "3.0.1",
  "info": {
    "title": "App Review Monitor",
    "description": "App review monitor that triages new App Store and Google Play reviews into bugs, billing complaints and feature requests, with similar reviews grouped and a flag when the rating drops. One row per new review, one digest per app, alerts to Slack. $0.40 per 1,000 reviews.",
    "version": "0.1",
    "x-build-id": "1g9PJRAamDP8vQhtn"
  },
  "servers": [
    {
      "url": "https://api.apify.com/v2"
    }
  ],
  "paths": {
    "/acts/dami_studio~app-review-triage-monitor/run-sync-get-dataset-items": {
      "post": {
        "operationId": "run-sync-get-dataset-items-dami_studio-app-review-triage-monitor",
        "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/dami_studio~app-review-triage-monitor/runs": {
      "post": {
        "operationId": "runs-sync-dami_studio-app-review-triage-monitor",
        "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/dami_studio~app-review-triage-monitor/run-sync": {
      "post": {
        "operationId": "run-sync-dami_studio-app-review-triage-monitor",
        "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",
        "required": [
          "apps"
        ],
        "properties": {
          "apps": {
            "title": "Apps to monitor",
            "type": "array",
            "description": "Each app: an optional label plus an App Store URL and/or a Google Play URL. You can monitor one store or both, reviews are unified."
          },
          "competitorApps": {
            "title": "Competitor apps (optional)",
            "type": "array",
            "description": "Same shape as 'apps'. If provided, the run includes a comparison of competitors' new-review theme volume.",
            "default": []
          },
          "weeklyReport": {
            "title": "Generate report artifact",
            "type": "boolean",
            "description": "Write a forwardable HTML + Markdown triage report to the run's key-value store (REPORT.html / REPORT.md).",
            "default": true
          },
          "useLLMTriage": {
            "title": "Enable the AI boost when a key is present",
            "type": "boolean",
            "description": "On by default, but it does nothing unless you add your own Anthropic key above. Set to off to force the built-in rules even if a key is present.",
            "default": true
          },
          "country": {
            "title": "Store country",
            "type": "string",
            "description": "Two-letter store country code (e.g. us, gb, de, fr, jp). On the App Store it picks that country's reviews. On Google Play it sets where the app's rating is read from.",
            "default": "us"
          },
          "language": {
            "title": "Review language",
            "enum": [
              "en",
              "es",
              "pt",
              "fr",
              "de",
              "it",
              "tr",
              "id",
              "ru"
            ],
            "type": "string",
            "description": "Google Play sends the reviews written in this language. The sorting reads this language in the reviews of both stores, along with English.",
            "default": "en"
          },
          "maxReviewsPerRun": {
            "title": "Max reviews per app per run",
            "minimum": 10,
            "maximum": 5000,
            "type": "integer",
            "description": "Upper bound on reviews fetched per app per store, most-recent first. The diff means you only pay to triage the NEW ones.",
            "default": 100
          },
          "readAllNewReviews": {
            "title": "Read every new review since the last run",
            "type": "boolean",
            "description": "Off by default. Turn it on and a run no longer stops at the max above: it keeps reading each store's newest reviews until it gets back to the ones the last run delivered, so a busy app loses none between runs. Each new review costs the same as without it. The first run with this on reads up to the max, to know where to start. A run brings up to 10,000 new Google Play reviews and 5,000 App Store reviews per app; any more come with the next run, and a free note row says so. Competitor apps keep to the max.",
            "default": false
          },
          "onlyNewSinceLastRun": {
            "title": "Only new since last run",
            "type": "boolean",
            "description": "Emit and triage only reviews that are new or changed since the last scheduled run (recommended, this is what makes it a monitor, not a dumper).",
            "default": true
          },
          "detectBugsCrashes": {
            "title": "Flag bugs & crashes",
            "type": "boolean",
            "description": "Surface bug/crash reviews as urgent items (with text + version).",
            "default": true
          },
          "detectBillingComplaints": {
            "title": "Flag billing complaints",
            "type": "boolean",
            "description": "Surface billing/refund/subscription reviews as urgent items.",
            "default": true
          },
          "detectFeatureRequests": {
            "title": "Flag feature requests",
            "type": "boolean",
            "description": "Count feature-request reviews separately.",
            "default": true
          },
          "detectRatingDrops": {
            "title": "Detect rating drops",
            "type": "boolean",
            "description": "Alert when an app's blended (cross-store) rating drops vs the last snapshot.",
            "default": true
          },
          "clusterThemes": {
            "title": "Cluster recurring themes",
            "type": "boolean",
            "description": "Group similar new reviews (e.g. '5 new reviews mention login failure after v4.2').",
            "default": true
          },
          "webhookUrl": {
            "title": "Webhook / Slack URL",
            "type": "string",
            "description": "Optional. POST a compact JSON summary here after each run. A Slack incoming-webhook URL works directly (uses the 'text' field).",
            "default": ""
          },
          "anthropicApiKey": {
            "title": "Your Anthropic API key (optional accuracy boost)",
            "type": "string",
            "description": "Optional. The built-in rules sort every review without a key. If you add your own Anthropic key, only the ~1-in-4 ambiguous reviews (sarcasm, mixed feedback, no clear keyword) get a sharper second look for a more accurate call. Your key, billed to your own Anthropic account, private to your runs. Get one at console.anthropic.com. Leave blank to stay on rules alone."
          }
        }
      },
      "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
                  },
                  "PROXY_UNBLOCKER_UNITS": {
                    "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
                  },
                  "PROXY_UNBLOCKER_UNITS": {
                    "type": "integer",
                    "example": 0
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}