{
  "openapi": "3.0.4",
  "info": {
    "title": "ASO.dev Developer API",
    "description": "Developer-facing API and documentation for ASO.dev integrations.\n\n### Request rate limits\n\nLimits apply per API key to authenticated `/v1` requests.\n\n| Requests | Limit | Average requests/second |\n|---|---:|---:|\n| All requests, including dry runs | 120 per UTC minute | 2 |\n| All requests, including dry runs | 50,000 per UTC day | 0.579 |\n| Dry runs (`dry_run=true`), additional limit | 1 per 3 seconds | 0.333 |\n\nThe per-second figures are averages, not separate per-second limits. These quotas use fixed windows. A dry run counts toward both general limits and its additional dry-run limit.\n\nWhen one of these request-rate limits is exceeded, the API returns HTTP `429` with `Retry-After` and `quota_scope`, `quota_limit_type`, `quota_limit`, and `quota_window_seconds` in the response body. Successful responses do not include a remaining-request count. Operation-specific quotas may also apply.",
    "version": "v1"
  },
  "paths": {
    "/v1/apps/keywords/rankings/movers": {
      "post": {
        "tags": [
          "App Keyword Rankings"
        ],
        "summary": "App keyword rankings: growing or falling keywords.",
        "description": "Uses stored app keyword ranks over a period ending yesterday UTC.\n\nCost: The same price applies to delta and table_trend, all periods and both directions. ownership_factor=0.5 for non-manual apps owned by the authenticated user, otherwise 1. Empty results cost 0. Pre-call/dry-run estimates use limit (default 50, max 200), capped by explicit normalized keyword count; no ranking lookup. Filters do not add a surcharge. The account balance and key monthly cap must cover this upper estimate; unused credits are refunded after the response.\n\nBilling unit: `keyword_mover`. Use `dry_run=true` to return an upper estimate without reading rankings. Final usage is based on returned keywords; unused reserved credits are refunded.",
        "operationId": "getAppKeywordRankingsMovers",
        "parameters": [
          {
            "name": "dry_run",
            "in": "query",
            "description": "Set to true to return only the estimated usage and credits for this request. Dry-run requests do not execute the operation and do not debit the account balance.",
            "schema": {
              "type": "boolean"
            },
            "example": false
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AppKeywordRankingsMoversRequest"
              },
              "example": {
                "app_id": "6445911688",
                "country": "US",
                "platform": "ios",
                "direction": "growing",
                "calculation": "delta",
                "period_days": 7,
                "limit": 50,
                "min_change": 1
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/AppKeywordRankingsMoversRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/AppKeywordRankingsMoversRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AppKeywordRankingsMoversResponse"
                }
              }
            }
          },
          "400": {
            "description": "Validation failed. Body is ValidationProblemDetails."
          },
          "401": {
            "description": "Missing or invalid X-API-Key. Body is ProblemDetails with error_code=unauthorized."
          },
          "402": {
            "description": "Developer account credits are insufficient. Body is ProblemDetails with error_code=insufficient_credits."
          },
          "403": {
            "description": "Operation or data scope is not allowed. Body is ProblemDetails with error_code."
          },
          "429": {
            "description": "API key rate limit, dry-run rate limit, no-data rate guard, operation quota, or API key monthly credit limit exceeded. Rate-limit, no-data, and operation-quota responses include Retry-After and identify the exact quota. no_data_rate_limit_exceeded also includes the block reason, unlock time, and evaluated ratio.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the exhausted window resets or the temporary key block expires.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicApiRateLimitProblemDetails"
                },
                "examples": {
                  "minute_limit": {
                    "summary": "API key minute limit exceeded",
                    "value": {
                      "type": "https://developer.aso.dev/errors/operation_quota_exceeded",
                      "title": "Too Many Requests",
                      "status": 429,
                      "detail": "Public API key rate limit exceeded: 120 requests per minute.",
                      "error_code": "operation_quota_exceeded",
                      "request_id": "req_01JEXAMPLE",
                      "quota_scope": "api",
                      "quota_limit_type": "minute",
                      "quota_limit": 120,
                      "quota_window_seconds": 60
                    }
                  },
                  "no_data_block": {
                    "summary": "API key temporarily blocked by the no-data guard",
                    "value": {
                      "type": "https://developer.aso.dev/errors/no_data_rate_limit_exceeded",
                      "title": "Too Many Requests",
                      "status": 429,
                      "detail": "Public API key is temporarily blocked until 2026-07-30T15:05:00.0000000+00:00: no_data rate 81.09% (163 of 201 data requests) exceeded 80% after more than 200 requests in the trailing 900 seconds.",
                      "error_code": "no_data_rate_limit_exceeded",
                      "request_id": "req_01JEXAMPLE",
                      "quota_scope": "no_data",
                      "quota_limit_type": "ratio",
                      "quota_limit": 80,
                      "quota_window_seconds": 900,
                      "block_reason": "no_data_rate_exceeded",
                      "blocked_until_utc": "2026-07-30T15:05:00+00:00",
                      "evaluated_requests": 201,
                      "no_data_requests": 163,
                      "no_data_rate_percent": 81.09
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "An unexpected server-side failure occurred. Body is ProblemDetails with error_code=internal_server_error and the request_id used for support correlation.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "internal_server_error": {
                    "summary": "Unexpected server-side failure",
                    "value": {
                      "type": "https://developer.aso.dev/errors/internal_server_error",
                      "title": "Internal server error",
                      "status": 500,
                      "detail": "An unexpected error occurred while processing the request.",
                      "error_code": "internal_server_error",
                      "request_id": "req_01JEXAMPLE"
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "Credit ledger or request-accounting storage is temporarily unavailable. Body is ProblemDetails with error_code=credit_ledger_unavailable or public_api_storage_unavailable."
          }
        },
        "security": [
          {
            "ApiKeyAuth": [ ]
          }
        ],
        "x-aso-pricing": {
          "currency": "credits",
          "billing_unit": "keyword_mover",
          "cost": "The same price applies to delta and table_trend, all periods and both directions. ownership_factor=0.5 for non-manual apps owned by the authenticated user, otherwise 1. Empty results cost 0. Pre-call/dry-run estimates use limit (default 50, max 200), capped by explicit normalized keyword count; no ranking lookup. Filters do not add a surcharge. The account balance and key monthly cap must cover this upper estimate; unused credits are refunded after the response.",
          "formula": "ceil(returned_keywords * 2 * ownership_factor / 5)",
          "minimum_credits": 0,
          "dry_run_supported": true,
          "dry_run_parameter": "dry_run"
        }
      }
    },
    "/v1/apps/keywords/rankings/current": {
      "post": {
        "tags": [
          "App Keyword Rankings"
        ],
        "summary": "App keyword rankings: yesterday and today.",
        "description": "With keywords, returns stored ranks for the selected terms. Omit keywords for\nRanked Keywords: all known keyword-date rows for the app, with cursor pagination.\nBoth modes return yesterday and today UTC; current does not mean a live lookup.\nStored unranked observations can have rank=null.\n\nCost: 6 credits per block of up to 250 distinct available keywords in the returned page, including yesterday and today; preserve the lower previous price for small responses. ownership_factor=0.5 for eligible non-manual owned apps, otherwise 1. Empty/unknown data costs 0. Units count available keyword-date observations. When keywords is omitted, limit still paginates rows (default 10, 0 for all). Pre-call estimates conservatively treat each requested row as a distinct keyword; cursor estimates use the saved page when available.\n\nBilling unit: `app_keyword_date`. Use `dry_run=true` to return an upper estimate. Final usage counts available data only; unknown data is free, while a stored observation with no rank is billable. Unused reserved credits are refunded and released from the key monthly cap. The balance and cap must cover the upper estimate.",
        "operationId": "getAppKeywordRankingsCurrent",
        "parameters": [
          {
            "name": "dry_run",
            "in": "query",
            "description": "Set to true to return only the estimated usage and credits for this request. Dry-run requests do not execute the operation and do not debit the account balance.",
            "schema": {
              "type": "boolean"
            },
            "example": false
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AppKeywordRankingsCurrentRequest"
              },
              "example": {
                "app_id": "6445911688",
                "country": "US",
                "platform": "ios",
                "keywords": [
                  "aso"
                ]
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/AppKeywordRankingsCurrentRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/AppKeywordRankingsCurrentRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AppKeywordRankingsCurrentResponse"
                }
              }
            }
          },
          "400": {
            "description": "Validation failed. Body is ValidationProblemDetails."
          },
          "401": {
            "description": "Missing or invalid X-API-Key. Body is ProblemDetails with error_code=unauthorized."
          },
          "402": {
            "description": "Developer account credits are insufficient. Body is ProblemDetails with error_code=insufficient_credits."
          },
          "403": {
            "description": "Operation or data scope is not allowed. Body is ProblemDetails with error_code."
          },
          "429": {
            "description": "API key rate limit, dry-run rate limit, no-data rate guard, operation quota, or API key monthly credit limit exceeded. Rate-limit, no-data, and operation-quota responses include Retry-After and identify the exact quota. no_data_rate_limit_exceeded also includes the block reason, unlock time, and evaluated ratio.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the exhausted window resets or the temporary key block expires.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicApiRateLimitProblemDetails"
                },
                "examples": {
                  "minute_limit": {
                    "summary": "API key minute limit exceeded",
                    "value": {
                      "type": "https://developer.aso.dev/errors/operation_quota_exceeded",
                      "title": "Too Many Requests",
                      "status": 429,
                      "detail": "Public API key rate limit exceeded: 120 requests per minute.",
                      "error_code": "operation_quota_exceeded",
                      "request_id": "req_01JEXAMPLE",
                      "quota_scope": "api",
                      "quota_limit_type": "minute",
                      "quota_limit": 120,
                      "quota_window_seconds": 60
                    }
                  },
                  "no_data_block": {
                    "summary": "API key temporarily blocked by the no-data guard",
                    "value": {
                      "type": "https://developer.aso.dev/errors/no_data_rate_limit_exceeded",
                      "title": "Too Many Requests",
                      "status": 429,
                      "detail": "Public API key is temporarily blocked until 2026-07-30T15:05:00.0000000+00:00: no_data rate 81.09% (163 of 201 data requests) exceeded 80% after more than 200 requests in the trailing 900 seconds.",
                      "error_code": "no_data_rate_limit_exceeded",
                      "request_id": "req_01JEXAMPLE",
                      "quota_scope": "no_data",
                      "quota_limit_type": "ratio",
                      "quota_limit": 80,
                      "quota_window_seconds": 900,
                      "block_reason": "no_data_rate_exceeded",
                      "blocked_until_utc": "2026-07-30T15:05:00+00:00",
                      "evaluated_requests": 201,
                      "no_data_requests": 163,
                      "no_data_rate_percent": 81.09
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "An unexpected server-side failure occurred. Body is ProblemDetails with error_code=internal_server_error and the request_id used for support correlation.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "internal_server_error": {
                    "summary": "Unexpected server-side failure",
                    "value": {
                      "type": "https://developer.aso.dev/errors/internal_server_error",
                      "title": "Internal server error",
                      "status": 500,
                      "detail": "An unexpected error occurred while processing the request.",
                      "error_code": "internal_server_error",
                      "request_id": "req_01JEXAMPLE"
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "Credit ledger or request-accounting storage is temporarily unavailable. Body is ProblemDetails with error_code=credit_ledger_unavailable or public_api_storage_unavailable."
          }
        },
        "security": [
          {
            "ApiKeyAuth": [ ]
          }
        ],
        "x-aso-pricing": {
          "currency": "credits",
          "billing_unit": "app_keyword_date",
          "cost": "6 credits per block of up to 250 distinct available keywords in the returned page, including yesterday and today; preserve the lower previous price for small responses. ownership_factor=0.5 for eligible non-manual owned apps, otherwise 1. Empty/unknown data costs 0. Units count available keyword-date observations. When keywords is omitted, limit still paginates rows (default 10, 0 for all). Pre-call estimates conservatively treat each requested row as a distinct keyword; cursor estimates use the saved page when available.",
          "formula": "min(6 * ceil(available_keywords / 250) * ownership_factor, 3 * ceil(available_keyword_dates * ownership_factor / 5))",
          "minimum_credits": 0,
          "dry_run_supported": true,
          "dry_run_parameter": "dry_run"
        }
      }
    },
    "/v1/apps/keywords/rankings/history": {
      "post": {
        "tags": [
          "App Keyword Rankings"
        ],
        "summary": "App keyword rankings: history.",
        "description": "Returns stored ranks for app-keyword pairs over the requested date range.\n\nCost: Per app-keyword pair with available data: 2 credits for the first available date + 0.2 per additional available date, capped at 12; use 0.3 per available date when lower. Sum all pairs and round up once after the eligible-own-app 50% discount. Missing dates cost 0; checked unranked observations are billable. Units count available app-keyword-date observations.\n\nBilling unit: `app_keyword_day`. Use `dry_run=true` to return an upper estimate. Final usage counts available data only; unknown data is free, while a stored observation with no rank is billable. Unused reserved credits are refunded and released from the key monthly cap. The balance and cap must cover the upper estimate.",
        "operationId": "getAppKeywordRankingsHistory",
        "parameters": [
          {
            "name": "dry_run",
            "in": "query",
            "description": "Set to true to return only the estimated usage and credits for this request. Dry-run requests do not execute the operation and do not debit the account balance.",
            "schema": {
              "type": "boolean"
            },
            "example": false
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AppKeywordRankingsHistoryRequest"
              },
              "example": {
                "app_ids": [
                  "6445911688"
                ],
                "country": "US",
                "platform": "ios",
                "keywords": [
                  "aso"
                ],
                "date_from": "2026-05-01",
                "date_to": "2026-05-02"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/AppKeywordRankingsHistoryRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/AppKeywordRankingsHistoryRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AppKeywordRankingsHistoryResponse"
                }
              }
            }
          },
          "400": {
            "description": "Validation failed. Body is ValidationProblemDetails."
          },
          "401": {
            "description": "Missing or invalid X-API-Key. Body is ProblemDetails with error_code=unauthorized."
          },
          "402": {
            "description": "Developer account credits are insufficient. Body is ProblemDetails with error_code=insufficient_credits."
          },
          "403": {
            "description": "Operation or data scope is not allowed. Body is ProblemDetails with error_code."
          },
          "429": {
            "description": "API key rate limit, dry-run rate limit, no-data rate guard, operation quota, or API key monthly credit limit exceeded. Rate-limit, no-data, and operation-quota responses include Retry-After and identify the exact quota. no_data_rate_limit_exceeded also includes the block reason, unlock time, and evaluated ratio.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the exhausted window resets or the temporary key block expires.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicApiRateLimitProblemDetails"
                },
                "examples": {
                  "minute_limit": {
                    "summary": "API key minute limit exceeded",
                    "value": {
                      "type": "https://developer.aso.dev/errors/operation_quota_exceeded",
                      "title": "Too Many Requests",
                      "status": 429,
                      "detail": "Public API key rate limit exceeded: 120 requests per minute.",
                      "error_code": "operation_quota_exceeded",
                      "request_id": "req_01JEXAMPLE",
                      "quota_scope": "api",
                      "quota_limit_type": "minute",
                      "quota_limit": 120,
                      "quota_window_seconds": 60
                    }
                  },
                  "no_data_block": {
                    "summary": "API key temporarily blocked by the no-data guard",
                    "value": {
                      "type": "https://developer.aso.dev/errors/no_data_rate_limit_exceeded",
                      "title": "Too Many Requests",
                      "status": 429,
                      "detail": "Public API key is temporarily blocked until 2026-07-30T15:05:00.0000000+00:00: no_data rate 81.09% (163 of 201 data requests) exceeded 80% after more than 200 requests in the trailing 900 seconds.",
                      "error_code": "no_data_rate_limit_exceeded",
                      "request_id": "req_01JEXAMPLE",
                      "quota_scope": "no_data",
                      "quota_limit_type": "ratio",
                      "quota_limit": 80,
                      "quota_window_seconds": 900,
                      "block_reason": "no_data_rate_exceeded",
                      "blocked_until_utc": "2026-07-30T15:05:00+00:00",
                      "evaluated_requests": 201,
                      "no_data_requests": 163,
                      "no_data_rate_percent": 81.09
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "An unexpected server-side failure occurred. Body is ProblemDetails with error_code=internal_server_error and the request_id used for support correlation.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "internal_server_error": {
                    "summary": "Unexpected server-side failure",
                    "value": {
                      "type": "https://developer.aso.dev/errors/internal_server_error",
                      "title": "Internal server error",
                      "status": 500,
                      "detail": "An unexpected error occurred while processing the request.",
                      "error_code": "internal_server_error",
                      "request_id": "req_01JEXAMPLE"
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "Credit ledger or request-accounting storage is temporarily unavailable. Body is ProblemDetails with error_code=credit_ledger_unavailable or public_api_storage_unavailable."
          }
        },
        "security": [
          {
            "ApiKeyAuth": [ ]
          }
        ],
        "x-aso-pricing": {
          "currency": "credits",
          "billing_unit": "app_keyword_day",
          "cost": "Per app-keyword pair with available data: 2 credits for the first available date + 0.2 per additional available date, capped at 12; use 0.3 per available date when lower. Sum all pairs and round up once after the eligible-own-app 50% discount. Missing dates cost 0; checked unranked observations are billable. Units count available app-keyword-date observations.",
          "formula": "ceil(sum(min(0.3 * available_dates, 2 + 0.2 * (available_dates - 1), 12) * ownership_factor))",
          "minimum_credits": 0,
          "dry_run_supported": true,
          "dry_run_parameter": "dry_run"
        }
      }
    },
    "/v1/apps/keywords/rankings/query": {
      "post": {
        "tags": [
          "App Keyword Rankings"
        ],
        "summary": "App keyword rankings: current or history.",
        "description": "Reads stored ranks for the explicitly supplied app and keywords. It does not read\na project keyword list or require the terms to be tracked. Omit both dates for\nyesterday and today UTC, or provide both dates for history. Prefer the current\nand history operations under App Keyword Rankings for new integrations.\n\nCost: Same pricing as rankings/current when dates are omitted (yesterday and today), or rankings/history when dates are provided. Available data only; eligible non-manual owned apps receive a 50% discount. Units count available keyword-date observations.\n\nBilling unit: `tracking_data_unit`. Use `dry_run=true` to return an upper estimate. Final usage counts available data only; unknown data is free, while a stored observation with no rank is billable. Unused reserved credits are refunded and released from the key monthly cap. The balance and cap must cover the upper estimate.",
        "operationId": "getAppKeywordRankings",
        "parameters": [
          {
            "name": "dry_run",
            "in": "query",
            "description": "Set to true to return only the estimated usage and credits for this request. Dry-run requests do not execute the operation and do not debit the account balance.",
            "schema": {
              "type": "boolean"
            },
            "example": false
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AppKeywordRankingsQueryRequest"
              },
              "example": {
                "app_id": "6445911688",
                "country": "US",
                "platform": "ios",
                "keywords": [
                  "aso"
                ]
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/AppKeywordRankingsQueryRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/AppKeywordRankingsQueryRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AppKeywordRankingsQueryResponse"
                }
              }
            }
          },
          "400": {
            "description": "Validation failed. Body is ValidationProblemDetails."
          },
          "401": {
            "description": "Missing or invalid X-API-Key. Body is ProblemDetails with error_code=unauthorized."
          },
          "402": {
            "description": "Developer account credits are insufficient. Body is ProblemDetails with error_code=insufficient_credits."
          },
          "403": {
            "description": "Operation or data scope is not allowed. Body is ProblemDetails with error_code."
          },
          "429": {
            "description": "API key rate limit, dry-run rate limit, no-data rate guard, operation quota, or API key monthly credit limit exceeded. Rate-limit, no-data, and operation-quota responses include Retry-After and identify the exact quota. no_data_rate_limit_exceeded also includes the block reason, unlock time, and evaluated ratio.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the exhausted window resets or the temporary key block expires.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicApiRateLimitProblemDetails"
                },
                "examples": {
                  "minute_limit": {
                    "summary": "API key minute limit exceeded",
                    "value": {
                      "type": "https://developer.aso.dev/errors/operation_quota_exceeded",
                      "title": "Too Many Requests",
                      "status": 429,
                      "detail": "Public API key rate limit exceeded: 120 requests per minute.",
                      "error_code": "operation_quota_exceeded",
                      "request_id": "req_01JEXAMPLE",
                      "quota_scope": "api",
                      "quota_limit_type": "minute",
                      "quota_limit": 120,
                      "quota_window_seconds": 60
                    }
                  },
                  "no_data_block": {
                    "summary": "API key temporarily blocked by the no-data guard",
                    "value": {
                      "type": "https://developer.aso.dev/errors/no_data_rate_limit_exceeded",
                      "title": "Too Many Requests",
                      "status": 429,
                      "detail": "Public API key is temporarily blocked until 2026-07-30T15:05:00.0000000+00:00: no_data rate 81.09% (163 of 201 data requests) exceeded 80% after more than 200 requests in the trailing 900 seconds.",
                      "error_code": "no_data_rate_limit_exceeded",
                      "request_id": "req_01JEXAMPLE",
                      "quota_scope": "no_data",
                      "quota_limit_type": "ratio",
                      "quota_limit": 80,
                      "quota_window_seconds": 900,
                      "block_reason": "no_data_rate_exceeded",
                      "blocked_until_utc": "2026-07-30T15:05:00+00:00",
                      "evaluated_requests": 201,
                      "no_data_requests": 163,
                      "no_data_rate_percent": 81.09
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "An unexpected server-side failure occurred. Body is ProblemDetails with error_code=internal_server_error and the request_id used for support correlation.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "internal_server_error": {
                    "summary": "Unexpected server-side failure",
                    "value": {
                      "type": "https://developer.aso.dev/errors/internal_server_error",
                      "title": "Internal server error",
                      "status": 500,
                      "detail": "An unexpected error occurred while processing the request.",
                      "error_code": "internal_server_error",
                      "request_id": "req_01JEXAMPLE"
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "Credit ledger or request-accounting storage is temporarily unavailable. Body is ProblemDetails with error_code=credit_ledger_unavailable or public_api_storage_unavailable."
          }
        },
        "security": [
          {
            "ApiKeyAuth": [ ]
          }
        ],
        "x-aso-pricing": {
          "currency": "credits",
          "billing_unit": "tracking_data_unit",
          "cost": "Same pricing as rankings/current when dates are omitted (yesterday and today), or rankings/history when dates are provided. Available data only; eligible non-manual owned apps receive a 50% discount. Units count available keyword-date observations.",
          "formula": "dates_omitted ? current_pricing : ceil(sum(min(0.3 * available_dates, 2 + 0.2 * (available_dates - 1), 12) * ownership_factor))",
          "minimum_credits": 0,
          "dry_run_supported": true,
          "dry_run_parameter": "dry_run"
        }
      }
    },
    "/v1/apps/charts/query": {
      "post": {
        "tags": [
          "AppCharts"
        ],
        "summary": "Returns stored daily top apps for one App Store category chart.",
        "description": "Cost: 4 credits per 200 returned apps, proportional and rounded up once per response. 200 rows cost 4 credits, 500 cost 10; empty results 0. Pre-call/dry-run uses requested limit (default 500, max 500).\n\nBilling unit: `app_chart_row`. Use `dry_run=true` to estimate the upper reservation from the requested limit. Final usage counts returned rows only; unused reserved credits are refunded and released from the key monthly cap. Empty results cost 0.",
        "operationId": "queryAppChart",
        "parameters": [
          {
            "name": "dry_run",
            "in": "query",
            "description": "Set to true to return only the estimated usage and credits for this request. Dry-run requests do not execute the operation and do not debit the account balance.",
            "schema": {
              "type": "boolean"
            },
            "example": false
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AppChartQueryRequest"
              },
              "example": {
                "country": "US",
                "lang": "en-US",
                "platform": "ios",
                "type": "free",
                "category_id": 6024,
                "limit": 500,
                "offset": 0
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/AppChartQueryRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/AppChartQueryRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AppChartQueryResponse"
                }
              }
            }
          },
          "400": {
            "description": "Validation failed. Body is ValidationProblemDetails."
          },
          "401": {
            "description": "Missing or invalid X-API-Key. Body is ProblemDetails with error_code=unauthorized."
          },
          "402": {
            "description": "Developer account credits are insufficient. Body is ProblemDetails with error_code=insufficient_credits."
          },
          "403": {
            "description": "Operation or data scope is not allowed. Body is ProblemDetails with error_code."
          },
          "429": {
            "description": "API key rate limit, dry-run rate limit, no-data rate guard, operation quota, or API key monthly credit limit exceeded. Rate-limit, no-data, and operation-quota responses include Retry-After and identify the exact quota. no_data_rate_limit_exceeded also includes the block reason, unlock time, and evaluated ratio.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the exhausted window resets or the temporary key block expires.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicApiRateLimitProblemDetails"
                },
                "examples": {
                  "minute_limit": {
                    "summary": "API key minute limit exceeded",
                    "value": {
                      "type": "https://developer.aso.dev/errors/operation_quota_exceeded",
                      "title": "Too Many Requests",
                      "status": 429,
                      "detail": "Public API key rate limit exceeded: 120 requests per minute.",
                      "error_code": "operation_quota_exceeded",
                      "request_id": "req_01JEXAMPLE",
                      "quota_scope": "api",
                      "quota_limit_type": "minute",
                      "quota_limit": 120,
                      "quota_window_seconds": 60
                    }
                  },
                  "no_data_block": {
                    "summary": "API key temporarily blocked by the no-data guard",
                    "value": {
                      "type": "https://developer.aso.dev/errors/no_data_rate_limit_exceeded",
                      "title": "Too Many Requests",
                      "status": 429,
                      "detail": "Public API key is temporarily blocked until 2026-07-30T15:05:00.0000000+00:00: no_data rate 81.09% (163 of 201 data requests) exceeded 80% after more than 200 requests in the trailing 900 seconds.",
                      "error_code": "no_data_rate_limit_exceeded",
                      "request_id": "req_01JEXAMPLE",
                      "quota_scope": "no_data",
                      "quota_limit_type": "ratio",
                      "quota_limit": 80,
                      "quota_window_seconds": 900,
                      "block_reason": "no_data_rate_exceeded",
                      "blocked_until_utc": "2026-07-30T15:05:00+00:00",
                      "evaluated_requests": 201,
                      "no_data_requests": 163,
                      "no_data_rate_percent": 81.09
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "An unexpected server-side failure occurred. Body is ProblemDetails with error_code=internal_server_error and the request_id used for support correlation.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "internal_server_error": {
                    "summary": "Unexpected server-side failure",
                    "value": {
                      "type": "https://developer.aso.dev/errors/internal_server_error",
                      "title": "Internal server error",
                      "status": 500,
                      "detail": "An unexpected error occurred while processing the request.",
                      "error_code": "internal_server_error",
                      "request_id": "req_01JEXAMPLE"
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "Credit ledger or request-accounting storage is temporarily unavailable. Body is ProblemDetails with error_code=credit_ledger_unavailable or public_api_storage_unavailable."
          }
        },
        "security": [
          {
            "ApiKeyAuth": [ ]
          }
        ],
        "x-aso-pricing": {
          "currency": "credits",
          "billing_unit": "app_chart_row",
          "cost": "4 credits per 200 returned apps, proportional and rounded up once per response. 200 rows cost 4 credits, 500 cost 10; empty results 0. Pre-call/dry-run uses requested limit (default 500, max 500).",
          "formula": "ceil(returned_rows * 4 / 200)",
          "minimum_credits": 1,
          "dry_run_supported": true,
          "dry_run_parameter": "dry_run"
        }
      }
    },
    "/v1/apps/charts/live": {
      "post": {
        "tags": [
          "AppCharts"
        ],
        "summary": "Returns current free, paid, or grossing apps from Apple for one App Store category chart. Free and paid use the scheduled AMP top-500 source; grossing uses the scheduled RSS top-200 source.",
        "description": "Cost: 0 credits when no rows are returned; otherwise 6 credits per chart request. Default limit 500, max limit 500; grossing returns up to 200 rows\n\nBilling unit: `app_chart_row`. Use `dry_run=true` to estimate 6 credits before fetching live data. Non-empty requests have the same fixed price regardless of limit, offset, or returned row count; no-data responses cost 0 credits. Usage units record actual returned rows.\n\nRequest timeout: `10` minutes.",
        "operationId": "getAppChartLive",
        "parameters": [
          {
            "name": "dry_run",
            "in": "query",
            "description": "Set to true to return only the estimated usage and credits for this request. Dry-run requests do not execute the operation and do not debit the account balance.",
            "schema": {
              "type": "boolean"
            },
            "example": false
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AppChartLiveRequest"
              },
              "example": {
                "country": "US",
                "lang": "en-US",
                "platform": "ios",
                "type": "free",
                "category_id": 6024,
                "limit": 500,
                "offset": 0
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/AppChartLiveRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/AppChartLiveRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AppChartQueryResponse"
                }
              }
            }
          },
          "400": {
            "description": "Validation failed. Body is ValidationProblemDetails."
          },
          "401": {
            "description": "Missing or invalid X-API-Key. Body is ProblemDetails with error_code=unauthorized."
          },
          "402": {
            "description": "Developer account credits are insufficient. Body is ProblemDetails with error_code=insufficient_credits."
          },
          "403": {
            "description": "Operation or data scope is not allowed. Body is ProblemDetails with error_code."
          },
          "429": {
            "description": "API key rate limit, dry-run rate limit, no-data rate guard, operation quota, or API key monthly credit limit exceeded. Rate-limit, no-data, and operation-quota responses include Retry-After and identify the exact quota. no_data_rate_limit_exceeded also includes the block reason, unlock time, and evaluated ratio.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the exhausted window resets or the temporary key block expires.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicApiRateLimitProblemDetails"
                },
                "examples": {
                  "minute_limit": {
                    "summary": "API key minute limit exceeded",
                    "value": {
                      "type": "https://developer.aso.dev/errors/operation_quota_exceeded",
                      "title": "Too Many Requests",
                      "status": 429,
                      "detail": "Public API key rate limit exceeded: 120 requests per minute.",
                      "error_code": "operation_quota_exceeded",
                      "request_id": "req_01JEXAMPLE",
                      "quota_scope": "api",
                      "quota_limit_type": "minute",
                      "quota_limit": 120,
                      "quota_window_seconds": 60
                    }
                  },
                  "no_data_block": {
                    "summary": "API key temporarily blocked by the no-data guard",
                    "value": {
                      "type": "https://developer.aso.dev/errors/no_data_rate_limit_exceeded",
                      "title": "Too Many Requests",
                      "status": 429,
                      "detail": "Public API key is temporarily blocked until 2026-07-30T15:05:00.0000000+00:00: no_data rate 81.09% (163 of 201 data requests) exceeded 80% after more than 200 requests in the trailing 900 seconds.",
                      "error_code": "no_data_rate_limit_exceeded",
                      "request_id": "req_01JEXAMPLE",
                      "quota_scope": "no_data",
                      "quota_limit_type": "ratio",
                      "quota_limit": 80,
                      "quota_window_seconds": 900,
                      "block_reason": "no_data_rate_exceeded",
                      "blocked_until_utc": "2026-07-30T15:05:00+00:00",
                      "evaluated_requests": 201,
                      "no_data_requests": 163,
                      "no_data_rate_percent": 81.09
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "An unexpected server-side failure occurred. Body is ProblemDetails with error_code=internal_server_error and the request_id used for support correlation.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "internal_server_error": {
                    "summary": "Unexpected server-side failure",
                    "value": {
                      "type": "https://developer.aso.dev/errors/internal_server_error",
                      "title": "Internal server error",
                      "status": 500,
                      "detail": "An unexpected error occurred while processing the request.",
                      "error_code": "internal_server_error",
                      "request_id": "req_01JEXAMPLE"
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "Credit ledger or request-accounting storage is temporarily unavailable. Body is ProblemDetails with error_code=credit_ledger_unavailable or public_api_storage_unavailable."
          }
        },
        "security": [
          {
            "ApiKeyAuth": [ ]
          }
        ],
        "x-aso-pricing": {
          "currency": "credits",
          "billing_unit": "app_chart_row",
          "cost": "0 credits when no rows are returned; otherwise 6 credits per chart request. Default limit 500, max limit 500; grossing returns up to 200 rows",
          "formula": "returned_rows == 0 ? 0 : 6",
          "minimum_credits": 6,
          "dry_run_supported": true,
          "dry_run_parameter": "dry_run"
        }
      }
    },
    "/v1/apps/charts/hourly": {
      "post": {
        "tags": [
          "AppCharts"
        ],
        "summary": "Returns an App Store category chart collected within the last hour, with its UTC snapshot timestamp. Missing or older snapshots are fetched live from Apple and saved before pagination; stale data is never returned.",
        "description": "Cost: 5 credits per 200 returned apps, proportional and rounded up once per response. 200 rows cost 5 credits, 300 cost 8, 500 cost 13; empty responses cost 0. Uses a snapshot no older than one hour; missing or expired charts are fetched live and saved in full before pagination, at the same price. Default limit 500, max limit 500\n\nBilling unit: `app_chart_row`. Use `dry_run=true` to estimate the upper reservation from the requested limit without reading, fetching or saving a chart. Final usage counts returned rows; unused credits are refunded and released from the key monthly cap. Empty responses cost 0. Default limit 500 estimates 13 credits; grossing charts are capped at 200 source rows and estimate at most 5 credits.\n\nRequest timeout: `10` minutes.",
        "operationId": "getAppChartHourly",
        "parameters": [
          {
            "name": "dry_run",
            "in": "query",
            "description": "Set to true to return only the estimated usage and credits for this request. Dry-run requests do not execute the operation and do not debit the account balance.",
            "schema": {
              "type": "boolean"
            },
            "example": false
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AppChartHourlyRequest"
              },
              "example": {
                "country": "US",
                "lang": "en-US",
                "platform": "ios",
                "type": "free",
                "category_id": 6024,
                "limit": 500,
                "offset": 0
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/AppChartHourlyRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/AppChartHourlyRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AppChartHourlyResponse"
                }
              }
            }
          },
          "400": {
            "description": "Validation failed. Body is ValidationProblemDetails."
          },
          "401": {
            "description": "Missing or invalid X-API-Key. Body is ProblemDetails with error_code=unauthorized."
          },
          "402": {
            "description": "Developer account credits are insufficient. Body is ProblemDetails with error_code=insufficient_credits."
          },
          "403": {
            "description": "Operation or data scope is not allowed. Body is ProblemDetails with error_code."
          },
          "429": {
            "description": "API key rate limit, dry-run rate limit, no-data rate guard, operation quota, or API key monthly credit limit exceeded. Rate-limit, no-data, and operation-quota responses include Retry-After and identify the exact quota. no_data_rate_limit_exceeded also includes the block reason, unlock time, and evaluated ratio.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the exhausted window resets or the temporary key block expires.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicApiRateLimitProblemDetails"
                },
                "examples": {
                  "minute_limit": {
                    "summary": "API key minute limit exceeded",
                    "value": {
                      "type": "https://developer.aso.dev/errors/operation_quota_exceeded",
                      "title": "Too Many Requests",
                      "status": 429,
                      "detail": "Public API key rate limit exceeded: 120 requests per minute.",
                      "error_code": "operation_quota_exceeded",
                      "request_id": "req_01JEXAMPLE",
                      "quota_scope": "api",
                      "quota_limit_type": "minute",
                      "quota_limit": 120,
                      "quota_window_seconds": 60
                    }
                  },
                  "no_data_block": {
                    "summary": "API key temporarily blocked by the no-data guard",
                    "value": {
                      "type": "https://developer.aso.dev/errors/no_data_rate_limit_exceeded",
                      "title": "Too Many Requests",
                      "status": 429,
                      "detail": "Public API key is temporarily blocked until 2026-07-30T15:05:00.0000000+00:00: no_data rate 81.09% (163 of 201 data requests) exceeded 80% after more than 200 requests in the trailing 900 seconds.",
                      "error_code": "no_data_rate_limit_exceeded",
                      "request_id": "req_01JEXAMPLE",
                      "quota_scope": "no_data",
                      "quota_limit_type": "ratio",
                      "quota_limit": 80,
                      "quota_window_seconds": 900,
                      "block_reason": "no_data_rate_exceeded",
                      "blocked_until_utc": "2026-07-30T15:05:00+00:00",
                      "evaluated_requests": 201,
                      "no_data_requests": 163,
                      "no_data_rate_percent": 81.09
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "An unexpected server-side failure occurred. Body is ProblemDetails with error_code=internal_server_error and the request_id used for support correlation.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "internal_server_error": {
                    "summary": "Unexpected server-side failure",
                    "value": {
                      "type": "https://developer.aso.dev/errors/internal_server_error",
                      "title": "Internal server error",
                      "status": 500,
                      "detail": "An unexpected error occurred while processing the request.",
                      "error_code": "internal_server_error",
                      "request_id": "req_01JEXAMPLE"
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "Credit ledger or request-accounting storage is temporarily unavailable. Body is ProblemDetails with error_code=credit_ledger_unavailable or public_api_storage_unavailable."
          }
        },
        "security": [
          {
            "ApiKeyAuth": [ ]
          }
        ],
        "x-aso-pricing": {
          "currency": "credits",
          "billing_unit": "app_chart_row",
          "cost": "5 credits per 200 returned apps, proportional and rounded up once per response. 200 rows cost 5 credits, 300 cost 8, 500 cost 13; empty responses cost 0. Uses a snapshot no older than one hour; missing or expired charts are fetched live and saved in full before pagination, at the same price. Default limit 500, max limit 500",
          "formula": "ceil(returned_rows * 5 / 200)",
          "minimum_credits": 1,
          "dry_run_supported": true,
          "dry_run_parameter": "dry_run"
        }
      }
    },
    "/v1/apps/charts/query-with-meta": {
      "post": {
        "tags": [
          "AppCharts"
        ],
        "summary": "Returns stored daily top apps and preview-refreshed app metadata for one App Store category chart.",
        "description": "Cost: 3 * max(1, ceil(returned_page_limit / 20)) credits; default limit 500, max limit 500\n\nBilling unit: `app_chart_row`. Use `dry_run=true` to return an exact estimate before running the operation.\n\nRequest timeout: `10` minutes.",
        "operationId": "queryAppChartWithMeta",
        "parameters": [
          {
            "name": "dry_run",
            "in": "query",
            "description": "Set to true to return only the estimated usage and credits for this request. Dry-run requests do not execute the operation and do not debit the account balance.",
            "schema": {
              "type": "boolean"
            },
            "example": false
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AppChartWithMetaQueryRequest"
              },
              "example": {
                "country": "US",
                "lang": "en-US",
                "platform": "ios",
                "type": "free",
                "category_id": 6024,
                "limit": 500,
                "offset": 0
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/AppChartWithMetaQueryRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/AppChartWithMetaQueryRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AppChartWithMetaQueryResponse"
                }
              }
            }
          },
          "400": {
            "description": "Validation failed. Body is ValidationProblemDetails."
          },
          "401": {
            "description": "Missing or invalid X-API-Key. Body is ProblemDetails with error_code=unauthorized."
          },
          "402": {
            "description": "Developer account credits are insufficient. Body is ProblemDetails with error_code=insufficient_credits."
          },
          "403": {
            "description": "Operation or data scope is not allowed. Body is ProblemDetails with error_code."
          },
          "429": {
            "description": "API key rate limit, dry-run rate limit, no-data rate guard, operation quota, or API key monthly credit limit exceeded. Rate-limit, no-data, and operation-quota responses include Retry-After and identify the exact quota. no_data_rate_limit_exceeded also includes the block reason, unlock time, and evaluated ratio.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the exhausted window resets or the temporary key block expires.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicApiRateLimitProblemDetails"
                },
                "examples": {
                  "minute_limit": {
                    "summary": "API key minute limit exceeded",
                    "value": {
                      "type": "https://developer.aso.dev/errors/operation_quota_exceeded",
                      "title": "Too Many Requests",
                      "status": 429,
                      "detail": "Public API key rate limit exceeded: 120 requests per minute.",
                      "error_code": "operation_quota_exceeded",
                      "request_id": "req_01JEXAMPLE",
                      "quota_scope": "api",
                      "quota_limit_type": "minute",
                      "quota_limit": 120,
                      "quota_window_seconds": 60
                    }
                  },
                  "no_data_block": {
                    "summary": "API key temporarily blocked by the no-data guard",
                    "value": {
                      "type": "https://developer.aso.dev/errors/no_data_rate_limit_exceeded",
                      "title": "Too Many Requests",
                      "status": 429,
                      "detail": "Public API key is temporarily blocked until 2026-07-30T15:05:00.0000000+00:00: no_data rate 81.09% (163 of 201 data requests) exceeded 80% after more than 200 requests in the trailing 900 seconds.",
                      "error_code": "no_data_rate_limit_exceeded",
                      "request_id": "req_01JEXAMPLE",
                      "quota_scope": "no_data",
                      "quota_limit_type": "ratio",
                      "quota_limit": 80,
                      "quota_window_seconds": 900,
                      "block_reason": "no_data_rate_exceeded",
                      "blocked_until_utc": "2026-07-30T15:05:00+00:00",
                      "evaluated_requests": 201,
                      "no_data_requests": 163,
                      "no_data_rate_percent": 81.09
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "An unexpected server-side failure occurred. Body is ProblemDetails with error_code=internal_server_error and the request_id used for support correlation.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "internal_server_error": {
                    "summary": "Unexpected server-side failure",
                    "value": {
                      "type": "https://developer.aso.dev/errors/internal_server_error",
                      "title": "Internal server error",
                      "status": 500,
                      "detail": "An unexpected error occurred while processing the request.",
                      "error_code": "internal_server_error",
                      "request_id": "req_01JEXAMPLE"
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "Credit ledger or request-accounting storage is temporarily unavailable. Body is ProblemDetails with error_code=credit_ledger_unavailable or public_api_storage_unavailable."
          }
        },
        "security": [
          {
            "ApiKeyAuth": [ ]
          }
        ],
        "x-aso-pricing": {
          "currency": "credits",
          "billing_unit": "app_chart_row",
          "cost": "3 * max(1, ceil(returned_page_limit / 20)) credits; default limit 500, max limit 500",
          "formula": "3 * max(1, ceil(limit / 20))",
          "minimum_credits": 3,
          "dry_run_supported": true,
          "dry_run_parameter": "dry_run"
        }
      }
    },
    "/v1/apps/rankings/current": {
      "post": {
        "tags": [
          "AppRankings"
        ],
        "summary": "Returns the latest stored category ranking positions for one app.",
        "description": "Cost: 3 credits per up to 25 returned ranking rows, capped at 6 credits per response; empty results 0. Pre-call/dry-run uses requested limit (default 100, max 1000).\n\nBilling unit: `app_ranking_row`. Use `dry_run=true` to estimate the upper reservation from the requested limit. Final usage counts returned rows only; unused reserved credits are refunded and released from the key monthly cap. Empty results cost 0.",
        "operationId": "getAppRankingsCurrent",
        "parameters": [
          {
            "name": "dry_run",
            "in": "query",
            "description": "Set to true to return only the estimated usage and credits for this request. Dry-run requests do not execute the operation and do not debit the account balance.",
            "schema": {
              "type": "boolean"
            },
            "example": false
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AppRankingsCurrentRequest"
              },
              "example": {
                "app_id": "375380948",
                "platform": "ios",
                "countries": [
                  "US"
                ],
                "types": [
                  "free"
                ],
                "category_ids": [
                  6024
                ],
                "limit": 100,
                "offset": 0
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/AppRankingsCurrentRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/AppRankingsCurrentRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AppRankingsResponse"
                }
              }
            }
          },
          "400": {
            "description": "Validation failed. Body is ValidationProblemDetails."
          },
          "401": {
            "description": "Missing or invalid X-API-Key. Body is ProblemDetails with error_code=unauthorized."
          },
          "402": {
            "description": "Developer account credits are insufficient. Body is ProblemDetails with error_code=insufficient_credits."
          },
          "403": {
            "description": "Operation or data scope is not allowed. Body is ProblemDetails with error_code."
          },
          "429": {
            "description": "API key rate limit, dry-run rate limit, no-data rate guard, operation quota, or API key monthly credit limit exceeded. Rate-limit, no-data, and operation-quota responses include Retry-After and identify the exact quota. no_data_rate_limit_exceeded also includes the block reason, unlock time, and evaluated ratio.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the exhausted window resets or the temporary key block expires.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicApiRateLimitProblemDetails"
                },
                "examples": {
                  "minute_limit": {
                    "summary": "API key minute limit exceeded",
                    "value": {
                      "type": "https://developer.aso.dev/errors/operation_quota_exceeded",
                      "title": "Too Many Requests",
                      "status": 429,
                      "detail": "Public API key rate limit exceeded: 120 requests per minute.",
                      "error_code": "operation_quota_exceeded",
                      "request_id": "req_01JEXAMPLE",
                      "quota_scope": "api",
                      "quota_limit_type": "minute",
                      "quota_limit": 120,
                      "quota_window_seconds": 60
                    }
                  },
                  "no_data_block": {
                    "summary": "API key temporarily blocked by the no-data guard",
                    "value": {
                      "type": "https://developer.aso.dev/errors/no_data_rate_limit_exceeded",
                      "title": "Too Many Requests",
                      "status": 429,
                      "detail": "Public API key is temporarily blocked until 2026-07-30T15:05:00.0000000+00:00: no_data rate 81.09% (163 of 201 data requests) exceeded 80% after more than 200 requests in the trailing 900 seconds.",
                      "error_code": "no_data_rate_limit_exceeded",
                      "request_id": "req_01JEXAMPLE",
                      "quota_scope": "no_data",
                      "quota_limit_type": "ratio",
                      "quota_limit": 80,
                      "quota_window_seconds": 900,
                      "block_reason": "no_data_rate_exceeded",
                      "blocked_until_utc": "2026-07-30T15:05:00+00:00",
                      "evaluated_requests": 201,
                      "no_data_requests": 163,
                      "no_data_rate_percent": 81.09
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "An unexpected server-side failure occurred. Body is ProblemDetails with error_code=internal_server_error and the request_id used for support correlation.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "internal_server_error": {
                    "summary": "Unexpected server-side failure",
                    "value": {
                      "type": "https://developer.aso.dev/errors/internal_server_error",
                      "title": "Internal server error",
                      "status": 500,
                      "detail": "An unexpected error occurred while processing the request.",
                      "error_code": "internal_server_error",
                      "request_id": "req_01JEXAMPLE"
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "Credit ledger or request-accounting storage is temporarily unavailable. Body is ProblemDetails with error_code=credit_ledger_unavailable or public_api_storage_unavailable."
          }
        },
        "security": [
          {
            "ApiKeyAuth": [ ]
          }
        ],
        "x-aso-pricing": {
          "currency": "credits",
          "billing_unit": "app_ranking_row",
          "cost": "3 credits per up to 25 returned ranking rows, capped at 6 credits per response; empty results 0. Pre-call/dry-run uses requested limit (default 100, max 1000).",
          "formula": "min(6, 3 * ceil(returned_rows / 25))",
          "minimum_credits": 3,
          "dry_run_supported": true,
          "dry_run_parameter": "dry_run"
        }
      }
    },
    "/v1/apps/rankings/history": {
      "post": {
        "tags": [
          "AppRankings"
        ],
        "summary": "Returns stored category ranking positions for one app over a date range.",
        "description": "Cost: 3 credits per up to 25 returned ranking rows; empty results 0. Pre-call/dry-run uses requested limit (default 100, max 1000).\n\nBilling unit: `app_ranking_row`. Use `dry_run=true` to estimate the upper reservation from the requested limit. Final usage counts returned rows only; unused reserved credits are refunded and released from the key monthly cap. Empty results cost 0.",
        "operationId": "getAppRankingsHistory",
        "parameters": [
          {
            "name": "dry_run",
            "in": "query",
            "description": "Set to true to return only the estimated usage and credits for this request. Dry-run requests do not execute the operation and do not debit the account balance.",
            "schema": {
              "type": "boolean"
            },
            "example": false
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AppRankingsHistoryRequest"
              },
              "example": {
                "app_id": "375380948",
                "platform": "ios",
                "countries": [
                  "US"
                ],
                "types": [
                  "free"
                ],
                "category_ids": [
                  6024
                ],
                "date_from": "2026-05-01",
                "date_to": "2026-05-02",
                "limit": 100,
                "offset": 0
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/AppRankingsHistoryRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/AppRankingsHistoryRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AppRankingsResponse"
                }
              }
            }
          },
          "400": {
            "description": "Validation failed. Body is ValidationProblemDetails."
          },
          "401": {
            "description": "Missing or invalid X-API-Key. Body is ProblemDetails with error_code=unauthorized."
          },
          "402": {
            "description": "Developer account credits are insufficient. Body is ProblemDetails with error_code=insufficient_credits."
          },
          "403": {
            "description": "Operation or data scope is not allowed. Body is ProblemDetails with error_code."
          },
          "429": {
            "description": "API key rate limit, dry-run rate limit, no-data rate guard, operation quota, or API key monthly credit limit exceeded. Rate-limit, no-data, and operation-quota responses include Retry-After and identify the exact quota. no_data_rate_limit_exceeded also includes the block reason, unlock time, and evaluated ratio.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the exhausted window resets or the temporary key block expires.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicApiRateLimitProblemDetails"
                },
                "examples": {
                  "minute_limit": {
                    "summary": "API key minute limit exceeded",
                    "value": {
                      "type": "https://developer.aso.dev/errors/operation_quota_exceeded",
                      "title": "Too Many Requests",
                      "status": 429,
                      "detail": "Public API key rate limit exceeded: 120 requests per minute.",
                      "error_code": "operation_quota_exceeded",
                      "request_id": "req_01JEXAMPLE",
                      "quota_scope": "api",
                      "quota_limit_type": "minute",
                      "quota_limit": 120,
                      "quota_window_seconds": 60
                    }
                  },
                  "no_data_block": {
                    "summary": "API key temporarily blocked by the no-data guard",
                    "value": {
                      "type": "https://developer.aso.dev/errors/no_data_rate_limit_exceeded",
                      "title": "Too Many Requests",
                      "status": 429,
                      "detail": "Public API key is temporarily blocked until 2026-07-30T15:05:00.0000000+00:00: no_data rate 81.09% (163 of 201 data requests) exceeded 80% after more than 200 requests in the trailing 900 seconds.",
                      "error_code": "no_data_rate_limit_exceeded",
                      "request_id": "req_01JEXAMPLE",
                      "quota_scope": "no_data",
                      "quota_limit_type": "ratio",
                      "quota_limit": 80,
                      "quota_window_seconds": 900,
                      "block_reason": "no_data_rate_exceeded",
                      "blocked_until_utc": "2026-07-30T15:05:00+00:00",
                      "evaluated_requests": 201,
                      "no_data_requests": 163,
                      "no_data_rate_percent": 81.09
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "An unexpected server-side failure occurred. Body is ProblemDetails with error_code=internal_server_error and the request_id used for support correlation.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "internal_server_error": {
                    "summary": "Unexpected server-side failure",
                    "value": {
                      "type": "https://developer.aso.dev/errors/internal_server_error",
                      "title": "Internal server error",
                      "status": 500,
                      "detail": "An unexpected error occurred while processing the request.",
                      "error_code": "internal_server_error",
                      "request_id": "req_01JEXAMPLE"
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "Credit ledger or request-accounting storage is temporarily unavailable. Body is ProblemDetails with error_code=credit_ledger_unavailable or public_api_storage_unavailable."
          }
        },
        "security": [
          {
            "ApiKeyAuth": [ ]
          }
        ],
        "x-aso-pricing": {
          "currency": "credits",
          "billing_unit": "app_ranking_row",
          "cost": "3 credits per up to 25 returned ranking rows; empty results 0. Pre-call/dry-run uses requested limit (default 100, max 1000).",
          "formula": "3 * ceil(returned_rows / 25)",
          "minimum_credits": 3,
          "dry_run_supported": true,
          "dry_run_parameter": "dry_run"
        }
      }
    },
    "/v1/apps/reviews/query": {
      "post": {
        "tags": [
          "AppReviews"
        ],
        "summary": "Returns stored App Store reviews for one app from newest to oldest.",
        "description": "Cost: 9 credits per up to 100 returned reviews; empty results 0. Pre-call/dry-run uses requested limit (default 100, max 10000).\n\nBilling unit: `review`. Use `dry_run=true` to estimate the upper reservation from the requested limit. Final usage counts returned rows only; unused reserved credits are refunded and released from the key monthly cap. Empty results cost 0.",
        "operationId": "queryAppReviews",
        "parameters": [
          {
            "name": "dry_run",
            "in": "query",
            "description": "Set to true to return only the estimated usage and credits for this request. Dry-run requests do not execute the operation and do not debit the account balance.",
            "schema": {
              "type": "boolean"
            },
            "example": false
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AppReviewsQueryRequest"
              },
              "example": {
                "app_id": "375380948",
                "countries": [
                  "US"
                ],
                "date_from": "2026-05-01",
                "date_to": "2026-05-02",
                "limit": 100,
                "offset": 0
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/AppReviewsQueryRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/AppReviewsQueryRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AppReviewsQueryResponse"
                }
              }
            }
          },
          "400": {
            "description": "Validation failed. Body is ValidationProblemDetails."
          },
          "401": {
            "description": "Missing or invalid X-API-Key. Body is ProblemDetails with error_code=unauthorized."
          },
          "402": {
            "description": "Developer account credits are insufficient. Body is ProblemDetails with error_code=insufficient_credits."
          },
          "403": {
            "description": "Operation or data scope is not allowed. Body is ProblemDetails with error_code."
          },
          "429": {
            "description": "API key rate limit, dry-run rate limit, no-data rate guard, operation quota, or API key monthly credit limit exceeded. Rate-limit, no-data, and operation-quota responses include Retry-After and identify the exact quota. no_data_rate_limit_exceeded also includes the block reason, unlock time, and evaluated ratio.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the exhausted window resets or the temporary key block expires.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicApiRateLimitProblemDetails"
                },
                "examples": {
                  "minute_limit": {
                    "summary": "API key minute limit exceeded",
                    "value": {
                      "type": "https://developer.aso.dev/errors/operation_quota_exceeded",
                      "title": "Too Many Requests",
                      "status": 429,
                      "detail": "Public API key rate limit exceeded: 120 requests per minute.",
                      "error_code": "operation_quota_exceeded",
                      "request_id": "req_01JEXAMPLE",
                      "quota_scope": "api",
                      "quota_limit_type": "minute",
                      "quota_limit": 120,
                      "quota_window_seconds": 60
                    }
                  },
                  "no_data_block": {
                    "summary": "API key temporarily blocked by the no-data guard",
                    "value": {
                      "type": "https://developer.aso.dev/errors/no_data_rate_limit_exceeded",
                      "title": "Too Many Requests",
                      "status": 429,
                      "detail": "Public API key is temporarily blocked until 2026-07-30T15:05:00.0000000+00:00: no_data rate 81.09% (163 of 201 data requests) exceeded 80% after more than 200 requests in the trailing 900 seconds.",
                      "error_code": "no_data_rate_limit_exceeded",
                      "request_id": "req_01JEXAMPLE",
                      "quota_scope": "no_data",
                      "quota_limit_type": "ratio",
                      "quota_limit": 80,
                      "quota_window_seconds": 900,
                      "block_reason": "no_data_rate_exceeded",
                      "blocked_until_utc": "2026-07-30T15:05:00+00:00",
                      "evaluated_requests": 201,
                      "no_data_requests": 163,
                      "no_data_rate_percent": 81.09
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "An unexpected server-side failure occurred. Body is ProblemDetails with error_code=internal_server_error and the request_id used for support correlation.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "internal_server_error": {
                    "summary": "Unexpected server-side failure",
                    "value": {
                      "type": "https://developer.aso.dev/errors/internal_server_error",
                      "title": "Internal server error",
                      "status": 500,
                      "detail": "An unexpected error occurred while processing the request.",
                      "error_code": "internal_server_error",
                      "request_id": "req_01JEXAMPLE"
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "Credit ledger or request-accounting storage is temporarily unavailable. Body is ProblemDetails with error_code=credit_ledger_unavailable or public_api_storage_unavailable."
          }
        },
        "security": [
          {
            "ApiKeyAuth": [ ]
          }
        ],
        "x-aso-pricing": {
          "currency": "credits",
          "billing_unit": "review",
          "cost": "9 credits per up to 100 returned reviews; empty results 0. Pre-call/dry-run uses requested limit (default 100, max 10000).",
          "formula": "9 * ceil(returned_rows / 100)",
          "minimum_credits": 9,
          "dry_run_supported": true,
          "dry_run_parameter": "dry_run"
        }
      }
    },
    "/v1/apps/details/summary": {
      "post": {
        "tags": [
          "Apps"
        ],
        "summary": "Returns compact stored metadata for one app and country, using the same fields as charts/query-with-meta.",
        "description": "Reads ASO.dev storage without refreshing Apple data. The optional platform selects ios, ipad, or mac metadata; default is ios.\n\nCost: 1 credit per compact stored app-country lookup\n\nBilling unit: `app_country`. Use `dry_run=true` to return an exact estimate before running the operation.",
        "operationId": "queryAppSummary",
        "parameters": [
          {
            "name": "dry_run",
            "in": "query",
            "description": "Set to true to return only the estimated usage and credits for this request. Dry-run requests do not execute the operation and do not debit the account balance.",
            "schema": {
              "type": "boolean"
            },
            "example": false
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AppSummaryQueryRequest"
              },
              "example": {
                "app_id": "6445911688",
                "country": "US"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/AppSummaryQueryRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/AppSummaryQueryRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AppSummaryResponse"
                }
              }
            }
          },
          "400": {
            "description": "Validation failed. Body is ValidationProblemDetails."
          },
          "401": {
            "description": "Missing or invalid X-API-Key. Body is ProblemDetails with error_code=unauthorized."
          },
          "402": {
            "description": "Developer account credits are insufficient. Body is ProblemDetails with error_code=insufficient_credits."
          },
          "403": {
            "description": "Operation or data scope is not allowed. Body is ProblemDetails with error_code."
          },
          "429": {
            "description": "API key rate limit, dry-run rate limit, no-data rate guard, operation quota, or API key monthly credit limit exceeded. Rate-limit, no-data, and operation-quota responses include Retry-After and identify the exact quota. no_data_rate_limit_exceeded also includes the block reason, unlock time, and evaluated ratio.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the exhausted window resets or the temporary key block expires.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicApiRateLimitProblemDetails"
                },
                "examples": {
                  "minute_limit": {
                    "summary": "API key minute limit exceeded",
                    "value": {
                      "type": "https://developer.aso.dev/errors/operation_quota_exceeded",
                      "title": "Too Many Requests",
                      "status": 429,
                      "detail": "Public API key rate limit exceeded: 120 requests per minute.",
                      "error_code": "operation_quota_exceeded",
                      "request_id": "req_01JEXAMPLE",
                      "quota_scope": "api",
                      "quota_limit_type": "minute",
                      "quota_limit": 120,
                      "quota_window_seconds": 60
                    }
                  },
                  "no_data_block": {
                    "summary": "API key temporarily blocked by the no-data guard",
                    "value": {
                      "type": "https://developer.aso.dev/errors/no_data_rate_limit_exceeded",
                      "title": "Too Many Requests",
                      "status": 429,
                      "detail": "Public API key is temporarily blocked until 2026-07-30T15:05:00.0000000+00:00: no_data rate 81.09% (163 of 201 data requests) exceeded 80% after more than 200 requests in the trailing 900 seconds.",
                      "error_code": "no_data_rate_limit_exceeded",
                      "request_id": "req_01JEXAMPLE",
                      "quota_scope": "no_data",
                      "quota_limit_type": "ratio",
                      "quota_limit": 80,
                      "quota_window_seconds": 900,
                      "block_reason": "no_data_rate_exceeded",
                      "blocked_until_utc": "2026-07-30T15:05:00+00:00",
                      "evaluated_requests": 201,
                      "no_data_requests": 163,
                      "no_data_rate_percent": 81.09
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "An unexpected server-side failure occurred. Body is ProblemDetails with error_code=internal_server_error and the request_id used for support correlation.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "internal_server_error": {
                    "summary": "Unexpected server-side failure",
                    "value": {
                      "type": "https://developer.aso.dev/errors/internal_server_error",
                      "title": "Internal server error",
                      "status": 500,
                      "detail": "An unexpected error occurred while processing the request.",
                      "error_code": "internal_server_error",
                      "request_id": "req_01JEXAMPLE"
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "Credit ledger or request-accounting storage is temporarily unavailable. Body is ProblemDetails with error_code=credit_ledger_unavailable or public_api_storage_unavailable."
          }
        },
        "security": [
          {
            "ApiKeyAuth": [ ]
          }
        ],
        "x-aso-pricing": {
          "currency": "credits",
          "billing_unit": "app_country",
          "cost": "1 credit per compact stored app-country lookup",
          "formula": "1",
          "minimum_credits": 1,
          "dry_run_supported": true,
          "dry_run_parameter": "dry_run"
        }
      }
    },
    "/v1/apps/details/live": {
      "post": {
        "tags": [
          "Apps"
        ],
        "summary": "Returns compact live App Store metadata for one app and country.",
        "description": "Refreshes Apple data and returns the same flat model as details/summary.\n\nCost: 9 credits per compact live app-country lookup\n\nBilling unit: `app_country`. Use `dry_run=true` to return an exact estimate before running the operation.",
        "operationId": "getAppDetailsLive",
        "parameters": [
          {
            "name": "dry_run",
            "in": "query",
            "description": "Set to true to return only the estimated usage and credits for this request. Dry-run requests do not execute the operation and do not debit the account balance.",
            "schema": {
              "type": "boolean"
            },
            "example": false
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AppDetailsLiveRequest"
              },
              "example": {
                "app_id": "6445911688",
                "country": "US"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/AppDetailsLiveRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/AppDetailsLiveRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AppSummaryResponse"
                }
              }
            }
          },
          "400": {
            "description": "Validation failed. Body is ValidationProblemDetails."
          },
          "401": {
            "description": "Missing or invalid X-API-Key. Body is ProblemDetails with error_code=unauthorized."
          },
          "402": {
            "description": "Developer account credits are insufficient. Body is ProblemDetails with error_code=insufficient_credits."
          },
          "403": {
            "description": "Operation or data scope is not allowed. Body is ProblemDetails with error_code."
          },
          "429": {
            "description": "API key rate limit, dry-run rate limit, no-data rate guard, operation quota, or API key monthly credit limit exceeded. Rate-limit, no-data, and operation-quota responses include Retry-After and identify the exact quota. no_data_rate_limit_exceeded also includes the block reason, unlock time, and evaluated ratio.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the exhausted window resets or the temporary key block expires.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicApiRateLimitProblemDetails"
                },
                "examples": {
                  "minute_limit": {
                    "summary": "API key minute limit exceeded",
                    "value": {
                      "type": "https://developer.aso.dev/errors/operation_quota_exceeded",
                      "title": "Too Many Requests",
                      "status": 429,
                      "detail": "Public API key rate limit exceeded: 120 requests per minute.",
                      "error_code": "operation_quota_exceeded",
                      "request_id": "req_01JEXAMPLE",
                      "quota_scope": "api",
                      "quota_limit_type": "minute",
                      "quota_limit": 120,
                      "quota_window_seconds": 60
                    }
                  },
                  "no_data_block": {
                    "summary": "API key temporarily blocked by the no-data guard",
                    "value": {
                      "type": "https://developer.aso.dev/errors/no_data_rate_limit_exceeded",
                      "title": "Too Many Requests",
                      "status": 429,
                      "detail": "Public API key is temporarily blocked until 2026-07-30T15:05:00.0000000+00:00: no_data rate 81.09% (163 of 201 data requests) exceeded 80% after more than 200 requests in the trailing 900 seconds.",
                      "error_code": "no_data_rate_limit_exceeded",
                      "request_id": "req_01JEXAMPLE",
                      "quota_scope": "no_data",
                      "quota_limit_type": "ratio",
                      "quota_limit": 80,
                      "quota_window_seconds": 900,
                      "block_reason": "no_data_rate_exceeded",
                      "blocked_until_utc": "2026-07-30T15:05:00+00:00",
                      "evaluated_requests": 201,
                      "no_data_requests": 163,
                      "no_data_rate_percent": 81.09
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "An unexpected server-side failure occurred. Body is ProblemDetails with error_code=internal_server_error and the request_id used for support correlation.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "internal_server_error": {
                    "summary": "Unexpected server-side failure",
                    "value": {
                      "type": "https://developer.aso.dev/errors/internal_server_error",
                      "title": "Internal server error",
                      "status": 500,
                      "detail": "An unexpected error occurred while processing the request.",
                      "error_code": "internal_server_error",
                      "request_id": "req_01JEXAMPLE"
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "Live App Store data, the credit ledger, or request-accounting storage is temporarily unavailable. Live lookup failures return error_code=live_data_unavailable; unavailable Public API runtime storage returns error_code=public_api_storage_unavailable.",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying a temporarily unavailable live lookup.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "live_data_unavailable": {
                    "summary": "Live App Store lookup temporarily unavailable",
                    "value": {
                      "type": "https://developer.aso.dev/errors/live_data_unavailable",
                      "title": "Live data temporarily unavailable",
                      "status": 503,
                      "detail": "Live App Store data could not be retrieved. Retry the request later.",
                      "error_code": "live_data_unavailable",
                      "request_id": "req_01JEXAMPLE",
                      "retryable": true
                    }
                  },
                  "public_api_storage_unavailable": {
                    "summary": "Public API request-accounting storage temporarily unavailable",
                    "value": {
                      "type": "https://developer.aso.dev/errors/public_api_storage_unavailable",
                      "title": "Service temporarily unavailable",
                      "status": 503,
                      "detail": "Public API request accounting storage is temporarily unavailable. Retry the request later.",
                      "error_code": "public_api_storage_unavailable",
                      "request_id": "req_01JEXAMPLE"
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "ApiKeyAuth": [ ]
          }
        ],
        "x-aso-pricing": {
          "currency": "credits",
          "billing_unit": "app_country",
          "cost": "9 credits per compact live app-country lookup",
          "formula": "9",
          "minimum_credits": 9,
          "dry_run_supported": true,
          "dry_run_parameter": "dry_run"
        }
      }
    },
    "/v1/auth/test": {
      "get": {
        "tags": [
          "Auth"
        ],
        "summary": "Verifies that the public API project, routing, JSON contract, and docs pipeline are alive.",
        "description": "Cost: 1 credit per successful request\n\nBilling unit: `request`. Use `dry_run=true` to return an exact estimate before running the operation.",
        "operationId": "testAuth",
        "parameters": [
          {
            "name": "X-Request-ID",
            "in": "header",
            "description": "Optional client request identifier.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "dry_run",
            "in": "query",
            "description": "Set to true to return only the estimated usage and credits for this request. Dry-run requests do not execute the operation and do not debit the account balance.",
            "schema": {
              "type": "boolean"
            },
            "example": false
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthTestResponse"
                }
              }
            }
          },
          "400": {
            "description": "Validation failed. Body is ValidationProblemDetails."
          },
          "401": {
            "description": "Missing or invalid X-API-Key. Body is ProblemDetails with error_code=unauthorized."
          },
          "402": {
            "description": "Developer account credits are insufficient. Body is ProblemDetails with error_code=insufficient_credits."
          },
          "403": {
            "description": "Operation or data scope is not allowed. Body is ProblemDetails with error_code."
          },
          "429": {
            "description": "API key rate limit, dry-run rate limit, no-data rate guard, operation quota, or API key monthly credit limit exceeded. Rate-limit, no-data, and operation-quota responses include Retry-After and identify the exact quota. no_data_rate_limit_exceeded also includes the block reason, unlock time, and evaluated ratio.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the exhausted window resets or the temporary key block expires.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicApiRateLimitProblemDetails"
                },
                "examples": {
                  "minute_limit": {
                    "summary": "API key minute limit exceeded",
                    "value": {
                      "type": "https://developer.aso.dev/errors/operation_quota_exceeded",
                      "title": "Too Many Requests",
                      "status": 429,
                      "detail": "Public API key rate limit exceeded: 120 requests per minute.",
                      "error_code": "operation_quota_exceeded",
                      "request_id": "req_01JEXAMPLE",
                      "quota_scope": "api",
                      "quota_limit_type": "minute",
                      "quota_limit": 120,
                      "quota_window_seconds": 60
                    }
                  },
                  "no_data_block": {
                    "summary": "API key temporarily blocked by the no-data guard",
                    "value": {
                      "type": "https://developer.aso.dev/errors/no_data_rate_limit_exceeded",
                      "title": "Too Many Requests",
                      "status": 429,
                      "detail": "Public API key is temporarily blocked until 2026-07-30T15:05:00.0000000+00:00: no_data rate 81.09% (163 of 201 data requests) exceeded 80% after more than 200 requests in the trailing 900 seconds.",
                      "error_code": "no_data_rate_limit_exceeded",
                      "request_id": "req_01JEXAMPLE",
                      "quota_scope": "no_data",
                      "quota_limit_type": "ratio",
                      "quota_limit": 80,
                      "quota_window_seconds": 900,
                      "block_reason": "no_data_rate_exceeded",
                      "blocked_until_utc": "2026-07-30T15:05:00+00:00",
                      "evaluated_requests": 201,
                      "no_data_requests": 163,
                      "no_data_rate_percent": 81.09
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "An unexpected server-side failure occurred. Body is ProblemDetails with error_code=internal_server_error and the request_id used for support correlation.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "internal_server_error": {
                    "summary": "Unexpected server-side failure",
                    "value": {
                      "type": "https://developer.aso.dev/errors/internal_server_error",
                      "title": "Internal server error",
                      "status": 500,
                      "detail": "An unexpected error occurred while processing the request.",
                      "error_code": "internal_server_error",
                      "request_id": "req_01JEXAMPLE"
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "Credit ledger or request-accounting storage is temporarily unavailable. Body is ProblemDetails with error_code=credit_ledger_unavailable or public_api_storage_unavailable."
          }
        },
        "security": [
          {
            "ApiKeyAuth": [ ]
          }
        ],
        "x-aso-pricing": {
          "currency": "credits",
          "billing_unit": "request",
          "cost": "1 credit per successful request",
          "formula": "1",
          "minimum_credits": 1,
          "dry_run_supported": true,
          "dry_run_parameter": "dry_run"
        }
      }
    },
    "/v1/developer/test": {
      "get": {
        "tags": [
          "Developer"
        ],
        "summary": "Verifies that the developer surface is active.",
        "description": "Cost: 1 credit per successful request\n\nBilling unit: `request`. Use `dry_run=true` to return an exact estimate before running the operation.",
        "operationId": "testDeveloperSurface",
        "parameters": [
          {
            "name": "dry_run",
            "in": "query",
            "description": "Set to true to return only the estimated usage and credits for this request. Dry-run requests do not execute the operation and do not debit the account balance.",
            "schema": {
              "type": "boolean"
            },
            "example": false
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SurfaceTestResponse"
                }
              }
            }
          },
          "400": {
            "description": "Validation failed. Body is ValidationProblemDetails."
          },
          "401": {
            "description": "Missing or invalid X-API-Key. Body is ProblemDetails with error_code=unauthorized."
          },
          "402": {
            "description": "Developer account credits are insufficient. Body is ProblemDetails with error_code=insufficient_credits."
          },
          "403": {
            "description": "Operation or data scope is not allowed. Body is ProblemDetails with error_code."
          },
          "429": {
            "description": "API key rate limit, dry-run rate limit, no-data rate guard, operation quota, or API key monthly credit limit exceeded. Rate-limit, no-data, and operation-quota responses include Retry-After and identify the exact quota. no_data_rate_limit_exceeded also includes the block reason, unlock time, and evaluated ratio.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the exhausted window resets or the temporary key block expires.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicApiRateLimitProblemDetails"
                },
                "examples": {
                  "minute_limit": {
                    "summary": "API key minute limit exceeded",
                    "value": {
                      "type": "https://developer.aso.dev/errors/operation_quota_exceeded",
                      "title": "Too Many Requests",
                      "status": 429,
                      "detail": "Public API key rate limit exceeded: 120 requests per minute.",
                      "error_code": "operation_quota_exceeded",
                      "request_id": "req_01JEXAMPLE",
                      "quota_scope": "api",
                      "quota_limit_type": "minute",
                      "quota_limit": 120,
                      "quota_window_seconds": 60
                    }
                  },
                  "no_data_block": {
                    "summary": "API key temporarily blocked by the no-data guard",
                    "value": {
                      "type": "https://developer.aso.dev/errors/no_data_rate_limit_exceeded",
                      "title": "Too Many Requests",
                      "status": 429,
                      "detail": "Public API key is temporarily blocked until 2026-07-30T15:05:00.0000000+00:00: no_data rate 81.09% (163 of 201 data requests) exceeded 80% after more than 200 requests in the trailing 900 seconds.",
                      "error_code": "no_data_rate_limit_exceeded",
                      "request_id": "req_01JEXAMPLE",
                      "quota_scope": "no_data",
                      "quota_limit_type": "ratio",
                      "quota_limit": 80,
                      "quota_window_seconds": 900,
                      "block_reason": "no_data_rate_exceeded",
                      "blocked_until_utc": "2026-07-30T15:05:00+00:00",
                      "evaluated_requests": 201,
                      "no_data_requests": 163,
                      "no_data_rate_percent": 81.09
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "An unexpected server-side failure occurred. Body is ProblemDetails with error_code=internal_server_error and the request_id used for support correlation.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "internal_server_error": {
                    "summary": "Unexpected server-side failure",
                    "value": {
                      "type": "https://developer.aso.dev/errors/internal_server_error",
                      "title": "Internal server error",
                      "status": 500,
                      "detail": "An unexpected error occurred while processing the request.",
                      "error_code": "internal_server_error",
                      "request_id": "req_01JEXAMPLE"
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "Credit ledger or request-accounting storage is temporarily unavailable. Body is ProblemDetails with error_code=credit_ledger_unavailable or public_api_storage_unavailable."
          }
        },
        "security": [
          {
            "ApiKeyAuth": [ ]
          }
        ],
        "x-aso-pricing": {
          "currency": "credits",
          "billing_unit": "request",
          "cost": "1 credit per successful request",
          "formula": "1",
          "minimum_credits": 1,
          "dry_run_supported": true,
          "dry_run_parameter": "dry_run"
        }
      }
    },
    "/v1/dictionaries/countries": {
      "get": {
        "tags": [
          "Dictionaries"
        ],
        "summary": "Returns all App Store countries supported by app and non-keyword endpoints.",
        "description": "Cost: 1 credit per successful request\n\nBilling unit: `request`. Use `dry_run=true` to return an exact estimate before running the operation.",
        "operationId": "getSupportedCountries",
        "parameters": [
          {
            "name": "dry_run",
            "in": "query",
            "description": "Set to true to return only the estimated usage and credits for this request. Dry-run requests do not execute the operation and do not debit the account balance.",
            "schema": {
              "type": "boolean"
            },
            "example": false
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SupportedCountriesResponse"
                }
              }
            }
          },
          "400": {
            "description": "Validation failed. Body is ValidationProblemDetails."
          },
          "401": {
            "description": "Missing or invalid X-API-Key. Body is ProblemDetails with error_code=unauthorized."
          },
          "402": {
            "description": "Developer account credits are insufficient. Body is ProblemDetails with error_code=insufficient_credits."
          },
          "403": {
            "description": "Operation or data scope is not allowed. Body is ProblemDetails with error_code."
          },
          "429": {
            "description": "API key rate limit, dry-run rate limit, no-data rate guard, operation quota, or API key monthly credit limit exceeded. Rate-limit, no-data, and operation-quota responses include Retry-After and identify the exact quota. no_data_rate_limit_exceeded also includes the block reason, unlock time, and evaluated ratio.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the exhausted window resets or the temporary key block expires.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicApiRateLimitProblemDetails"
                },
                "examples": {
                  "minute_limit": {
                    "summary": "API key minute limit exceeded",
                    "value": {
                      "type": "https://developer.aso.dev/errors/operation_quota_exceeded",
                      "title": "Too Many Requests",
                      "status": 429,
                      "detail": "Public API key rate limit exceeded: 120 requests per minute.",
                      "error_code": "operation_quota_exceeded",
                      "request_id": "req_01JEXAMPLE",
                      "quota_scope": "api",
                      "quota_limit_type": "minute",
                      "quota_limit": 120,
                      "quota_window_seconds": 60
                    }
                  },
                  "no_data_block": {
                    "summary": "API key temporarily blocked by the no-data guard",
                    "value": {
                      "type": "https://developer.aso.dev/errors/no_data_rate_limit_exceeded",
                      "title": "Too Many Requests",
                      "status": 429,
                      "detail": "Public API key is temporarily blocked until 2026-07-30T15:05:00.0000000+00:00: no_data rate 81.09% (163 of 201 data requests) exceeded 80% after more than 200 requests in the trailing 900 seconds.",
                      "error_code": "no_data_rate_limit_exceeded",
                      "request_id": "req_01JEXAMPLE",
                      "quota_scope": "no_data",
                      "quota_limit_type": "ratio",
                      "quota_limit": 80,
                      "quota_window_seconds": 900,
                      "block_reason": "no_data_rate_exceeded",
                      "blocked_until_utc": "2026-07-30T15:05:00+00:00",
                      "evaluated_requests": 201,
                      "no_data_requests": 163,
                      "no_data_rate_percent": 81.09
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "An unexpected server-side failure occurred. Body is ProblemDetails with error_code=internal_server_error and the request_id used for support correlation.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "internal_server_error": {
                    "summary": "Unexpected server-side failure",
                    "value": {
                      "type": "https://developer.aso.dev/errors/internal_server_error",
                      "title": "Internal server error",
                      "status": 500,
                      "detail": "An unexpected error occurred while processing the request.",
                      "error_code": "internal_server_error",
                      "request_id": "req_01JEXAMPLE"
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "Credit ledger or request-accounting storage is temporarily unavailable. Body is ProblemDetails with error_code=credit_ledger_unavailable or public_api_storage_unavailable."
          }
        },
        "security": [
          {
            "ApiKeyAuth": [ ]
          }
        ],
        "x-aso-pricing": {
          "currency": "credits",
          "billing_unit": "request",
          "cost": "1 credit per successful request",
          "formula": "1",
          "minimum_credits": 1,
          "dry_run_supported": true,
          "dry_run_parameter": "dry_run"
        }
      }
    },
    "/v1/dictionaries/keywords/countries": {
      "get": {
        "tags": [
          "Dictionaries"
        ],
        "summary": "Returns countries supported by keyword endpoints.",
        "description": "Cost: 1 credit per successful request\n\nBilling unit: `request`. Use `dry_run=true` to return an exact estimate before running the operation.",
        "operationId": "getSupportedKeywordCountries",
        "parameters": [
          {
            "name": "dry_run",
            "in": "query",
            "description": "Set to true to return only the estimated usage and credits for this request. Dry-run requests do not execute the operation and do not debit the account balance.",
            "schema": {
              "type": "boolean"
            },
            "example": false
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SupportedCountriesResponse"
                }
              }
            }
          },
          "400": {
            "description": "Validation failed. Body is ValidationProblemDetails."
          },
          "401": {
            "description": "Missing or invalid X-API-Key. Body is ProblemDetails with error_code=unauthorized."
          },
          "402": {
            "description": "Developer account credits are insufficient. Body is ProblemDetails with error_code=insufficient_credits."
          },
          "403": {
            "description": "Operation or data scope is not allowed. Body is ProblemDetails with error_code."
          },
          "429": {
            "description": "API key rate limit, dry-run rate limit, no-data rate guard, operation quota, or API key monthly credit limit exceeded. Rate-limit, no-data, and operation-quota responses include Retry-After and identify the exact quota. no_data_rate_limit_exceeded also includes the block reason, unlock time, and evaluated ratio.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the exhausted window resets or the temporary key block expires.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicApiRateLimitProblemDetails"
                },
                "examples": {
                  "minute_limit": {
                    "summary": "API key minute limit exceeded",
                    "value": {
                      "type": "https://developer.aso.dev/errors/operation_quota_exceeded",
                      "title": "Too Many Requests",
                      "status": 429,
                      "detail": "Public API key rate limit exceeded: 120 requests per minute.",
                      "error_code": "operation_quota_exceeded",
                      "request_id": "req_01JEXAMPLE",
                      "quota_scope": "api",
                      "quota_limit_type": "minute",
                      "quota_limit": 120,
                      "quota_window_seconds": 60
                    }
                  },
                  "no_data_block": {
                    "summary": "API key temporarily blocked by the no-data guard",
                    "value": {
                      "type": "https://developer.aso.dev/errors/no_data_rate_limit_exceeded",
                      "title": "Too Many Requests",
                      "status": 429,
                      "detail": "Public API key is temporarily blocked until 2026-07-30T15:05:00.0000000+00:00: no_data rate 81.09% (163 of 201 data requests) exceeded 80% after more than 200 requests in the trailing 900 seconds.",
                      "error_code": "no_data_rate_limit_exceeded",
                      "request_id": "req_01JEXAMPLE",
                      "quota_scope": "no_data",
                      "quota_limit_type": "ratio",
                      "quota_limit": 80,
                      "quota_window_seconds": 900,
                      "block_reason": "no_data_rate_exceeded",
                      "blocked_until_utc": "2026-07-30T15:05:00+00:00",
                      "evaluated_requests": 201,
                      "no_data_requests": 163,
                      "no_data_rate_percent": 81.09
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "An unexpected server-side failure occurred. Body is ProblemDetails with error_code=internal_server_error and the request_id used for support correlation.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "internal_server_error": {
                    "summary": "Unexpected server-side failure",
                    "value": {
                      "type": "https://developer.aso.dev/errors/internal_server_error",
                      "title": "Internal server error",
                      "status": 500,
                      "detail": "An unexpected error occurred while processing the request.",
                      "error_code": "internal_server_error",
                      "request_id": "req_01JEXAMPLE"
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "Credit ledger or request-accounting storage is temporarily unavailable. Body is ProblemDetails with error_code=credit_ledger_unavailable or public_api_storage_unavailable."
          }
        },
        "security": [
          {
            "ApiKeyAuth": [ ]
          }
        ],
        "x-aso-pricing": {
          "currency": "credits",
          "billing_unit": "request",
          "cost": "1 credit per successful request",
          "formula": "1",
          "minimum_credits": 1,
          "dry_run_supported": true,
          "dry_run_parameter": "dry_run"
        }
      }
    },
    "/v1/dictionaries/app-categories": {
      "get": {
        "tags": [
          "Dictionaries"
        ],
        "summary": "Returns App Store category ids supported by app ranking endpoints.",
        "description": "Cost: 1 credit per successful request\n\nBilling unit: `request`. Use `dry_run=true` to return an exact estimate before running the operation.",
        "operationId": "getSupportedAppCategories",
        "parameters": [
          {
            "name": "dry_run",
            "in": "query",
            "description": "Set to true to return only the estimated usage and credits for this request. Dry-run requests do not execute the operation and do not debit the account balance.",
            "schema": {
              "type": "boolean"
            },
            "example": false
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SupportedAppCategoriesResponse"
                }
              }
            }
          },
          "400": {
            "description": "Validation failed. Body is ValidationProblemDetails."
          },
          "401": {
            "description": "Missing or invalid X-API-Key. Body is ProblemDetails with error_code=unauthorized."
          },
          "402": {
            "description": "Developer account credits are insufficient. Body is ProblemDetails with error_code=insufficient_credits."
          },
          "403": {
            "description": "Operation or data scope is not allowed. Body is ProblemDetails with error_code."
          },
          "429": {
            "description": "API key rate limit, dry-run rate limit, no-data rate guard, operation quota, or API key monthly credit limit exceeded. Rate-limit, no-data, and operation-quota responses include Retry-After and identify the exact quota. no_data_rate_limit_exceeded also includes the block reason, unlock time, and evaluated ratio.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the exhausted window resets or the temporary key block expires.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicApiRateLimitProblemDetails"
                },
                "examples": {
                  "minute_limit": {
                    "summary": "API key minute limit exceeded",
                    "value": {
                      "type": "https://developer.aso.dev/errors/operation_quota_exceeded",
                      "title": "Too Many Requests",
                      "status": 429,
                      "detail": "Public API key rate limit exceeded: 120 requests per minute.",
                      "error_code": "operation_quota_exceeded",
                      "request_id": "req_01JEXAMPLE",
                      "quota_scope": "api",
                      "quota_limit_type": "minute",
                      "quota_limit": 120,
                      "quota_window_seconds": 60
                    }
                  },
                  "no_data_block": {
                    "summary": "API key temporarily blocked by the no-data guard",
                    "value": {
                      "type": "https://developer.aso.dev/errors/no_data_rate_limit_exceeded",
                      "title": "Too Many Requests",
                      "status": 429,
                      "detail": "Public API key is temporarily blocked until 2026-07-30T15:05:00.0000000+00:00: no_data rate 81.09% (163 of 201 data requests) exceeded 80% after more than 200 requests in the trailing 900 seconds.",
                      "error_code": "no_data_rate_limit_exceeded",
                      "request_id": "req_01JEXAMPLE",
                      "quota_scope": "no_data",
                      "quota_limit_type": "ratio",
                      "quota_limit": 80,
                      "quota_window_seconds": 900,
                      "block_reason": "no_data_rate_exceeded",
                      "blocked_until_utc": "2026-07-30T15:05:00+00:00",
                      "evaluated_requests": 201,
                      "no_data_requests": 163,
                      "no_data_rate_percent": 81.09
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "An unexpected server-side failure occurred. Body is ProblemDetails with error_code=internal_server_error and the request_id used for support correlation.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "internal_server_error": {
                    "summary": "Unexpected server-side failure",
                    "value": {
                      "type": "https://developer.aso.dev/errors/internal_server_error",
                      "title": "Internal server error",
                      "status": 500,
                      "detail": "An unexpected error occurred while processing the request.",
                      "error_code": "internal_server_error",
                      "request_id": "req_01JEXAMPLE"
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "Credit ledger or request-accounting storage is temporarily unavailable. Body is ProblemDetails with error_code=credit_ledger_unavailable or public_api_storage_unavailable."
          }
        },
        "security": [
          {
            "ApiKeyAuth": [ ]
          }
        ],
        "x-aso-pricing": {
          "currency": "credits",
          "billing_unit": "request",
          "cost": "1 credit per successful request",
          "formula": "1",
          "minimum_credits": 1,
          "dry_run_supported": true,
          "dry_run_parameter": "dry_run"
        }
      }
    },
    "/v1/keyword-lists": {
      "post": {
        "tags": [
          "Keyword Lists"
        ],
        "summary": "Keyword lists: list configured keywords.",
        "description": "Reads the project-owned keyword list for an app, country, and platform.\n\nCost: 1 credit per successful request\n\nBilling unit: `request`. Use `dry_run=true` to return an exact estimate before running the operation.",
        "operationId": "getKeywordLists",
        "parameters": [
          {
            "name": "dry_run",
            "in": "query",
            "description": "Set to true to return only the estimated usage and credits for this request. Dry-run requests do not execute the operation and do not debit the account balance.",
            "schema": {
              "type": "boolean"
            },
            "example": false
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/KeywordListsRequest"
              },
              "example": {
                "project_id": "demo_project",
                "app_id": "6445911688",
                "country": "US",
                "platform": "ios",
                "page": 1,
                "page_size": 50
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/KeywordListsRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/KeywordListsRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/KeywordListsResponse"
                }
              }
            }
          },
          "400": {
            "description": "Validation failed. Body is ValidationProblemDetails."
          },
          "401": {
            "description": "Missing or invalid X-API-Key. Body is ProblemDetails with error_code=unauthorized."
          },
          "402": {
            "description": "Developer account credits are insufficient. Body is ProblemDetails with error_code=insufficient_credits."
          },
          "403": {
            "description": "Operation or data scope is not allowed. Body is ProblemDetails with error_code."
          },
          "429": {
            "description": "API key rate limit, dry-run rate limit, no-data rate guard, operation quota, or API key monthly credit limit exceeded. Rate-limit, no-data, and operation-quota responses include Retry-After and identify the exact quota. no_data_rate_limit_exceeded also includes the block reason, unlock time, and evaluated ratio.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the exhausted window resets or the temporary key block expires.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicApiRateLimitProblemDetails"
                },
                "examples": {
                  "minute_limit": {
                    "summary": "API key minute limit exceeded",
                    "value": {
                      "type": "https://developer.aso.dev/errors/operation_quota_exceeded",
                      "title": "Too Many Requests",
                      "status": 429,
                      "detail": "Public API key rate limit exceeded: 120 requests per minute.",
                      "error_code": "operation_quota_exceeded",
                      "request_id": "req_01JEXAMPLE",
                      "quota_scope": "api",
                      "quota_limit_type": "minute",
                      "quota_limit": 120,
                      "quota_window_seconds": 60
                    }
                  },
                  "no_data_block": {
                    "summary": "API key temporarily blocked by the no-data guard",
                    "value": {
                      "type": "https://developer.aso.dev/errors/no_data_rate_limit_exceeded",
                      "title": "Too Many Requests",
                      "status": 429,
                      "detail": "Public API key is temporarily blocked until 2026-07-30T15:05:00.0000000+00:00: no_data rate 81.09% (163 of 201 data requests) exceeded 80% after more than 200 requests in the trailing 900 seconds.",
                      "error_code": "no_data_rate_limit_exceeded",
                      "request_id": "req_01JEXAMPLE",
                      "quota_scope": "no_data",
                      "quota_limit_type": "ratio",
                      "quota_limit": 80,
                      "quota_window_seconds": 900,
                      "block_reason": "no_data_rate_exceeded",
                      "blocked_until_utc": "2026-07-30T15:05:00+00:00",
                      "evaluated_requests": 201,
                      "no_data_requests": 163,
                      "no_data_rate_percent": 81.09
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "An unexpected server-side failure occurred. Body is ProblemDetails with error_code=internal_server_error and the request_id used for support correlation.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "internal_server_error": {
                    "summary": "Unexpected server-side failure",
                    "value": {
                      "type": "https://developer.aso.dev/errors/internal_server_error",
                      "title": "Internal server error",
                      "status": 500,
                      "detail": "An unexpected error occurred while processing the request.",
                      "error_code": "internal_server_error",
                      "request_id": "req_01JEXAMPLE"
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "Credit ledger or request-accounting storage is temporarily unavailable. Body is ProblemDetails with error_code=credit_ledger_unavailable or public_api_storage_unavailable."
          }
        },
        "security": [
          {
            "ApiKeyAuth": [ ]
          }
        ],
        "x-aso-pricing": {
          "currency": "credits",
          "billing_unit": "request",
          "cost": "1 credit per successful request",
          "formula": "1",
          "minimum_credits": 1,
          "dry_run_supported": true,
          "dry_run_parameter": "dry_run"
        }
      },
      "put": {
        "tags": [
          "Keyword Lists"
        ],
        "summary": "Keyword lists: replace configured keywords.",
        "description": "Updates monitoring configuration; the request does not fetch fresh ranks.\n\nCost: 1 credit per update request\n\nBilling unit: `request`. Use `dry_run=true` to return an exact estimate before running the operation.",
        "operationId": "replaceKeywordList",
        "parameters": [
          {
            "name": "dry_run",
            "in": "query",
            "description": "Set to true to return only the estimated usage and credits for this request. Dry-run requests do not execute the operation and do not debit the account balance.",
            "schema": {
              "type": "boolean"
            },
            "example": false
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ReplaceKeywordListRequest"
              },
              "example": {
                "project_id": "demo_project",
                "app_id": "6445911688",
                "country": "US",
                "platform": "ios",
                "keywords": [
                  "aso"
                ]
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/ReplaceKeywordListRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/ReplaceKeywordListRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/KeywordListMutationResponse"
                }
              }
            }
          },
          "400": {
            "description": "Validation failed. Body is ValidationProblemDetails."
          },
          "401": {
            "description": "Missing or invalid X-API-Key. Body is ProblemDetails with error_code=unauthorized."
          },
          "402": {
            "description": "Developer account credits are insufficient. Body is ProblemDetails with error_code=insufficient_credits."
          },
          "403": {
            "description": "Operation or data scope is not allowed. Body is ProblemDetails with error_code."
          },
          "429": {
            "description": "API key rate limit, dry-run rate limit, no-data rate guard, operation quota, or API key monthly credit limit exceeded. Rate-limit, no-data, and operation-quota responses include Retry-After and identify the exact quota. no_data_rate_limit_exceeded also includes the block reason, unlock time, and evaluated ratio.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the exhausted window resets or the temporary key block expires.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicApiRateLimitProblemDetails"
                },
                "examples": {
                  "minute_limit": {
                    "summary": "API key minute limit exceeded",
                    "value": {
                      "type": "https://developer.aso.dev/errors/operation_quota_exceeded",
                      "title": "Too Many Requests",
                      "status": 429,
                      "detail": "Public API key rate limit exceeded: 120 requests per minute.",
                      "error_code": "operation_quota_exceeded",
                      "request_id": "req_01JEXAMPLE",
                      "quota_scope": "api",
                      "quota_limit_type": "minute",
                      "quota_limit": 120,
                      "quota_window_seconds": 60
                    }
                  },
                  "no_data_block": {
                    "summary": "API key temporarily blocked by the no-data guard",
                    "value": {
                      "type": "https://developer.aso.dev/errors/no_data_rate_limit_exceeded",
                      "title": "Too Many Requests",
                      "status": 429,
                      "detail": "Public API key is temporarily blocked until 2026-07-30T15:05:00.0000000+00:00: no_data rate 81.09% (163 of 201 data requests) exceeded 80% after more than 200 requests in the trailing 900 seconds.",
                      "error_code": "no_data_rate_limit_exceeded",
                      "request_id": "req_01JEXAMPLE",
                      "quota_scope": "no_data",
                      "quota_limit_type": "ratio",
                      "quota_limit": 80,
                      "quota_window_seconds": 900,
                      "block_reason": "no_data_rate_exceeded",
                      "blocked_until_utc": "2026-07-30T15:05:00+00:00",
                      "evaluated_requests": 201,
                      "no_data_requests": 163,
                      "no_data_rate_percent": 81.09
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "An unexpected server-side failure occurred. Body is ProblemDetails with error_code=internal_server_error and the request_id used for support correlation.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "internal_server_error": {
                    "summary": "Unexpected server-side failure",
                    "value": {
                      "type": "https://developer.aso.dev/errors/internal_server_error",
                      "title": "Internal server error",
                      "status": 500,
                      "detail": "An unexpected error occurred while processing the request.",
                      "error_code": "internal_server_error",
                      "request_id": "req_01JEXAMPLE"
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "Credit ledger or request-accounting storage is temporarily unavailable. Body is ProblemDetails with error_code=credit_ledger_unavailable or public_api_storage_unavailable."
          }
        },
        "security": [
          {
            "ApiKeyAuth": [ ]
          }
        ],
        "x-aso-pricing": {
          "currency": "credits",
          "billing_unit": "request",
          "cost": "1 credit per update request",
          "formula": "1",
          "minimum_credits": 1,
          "dry_run_supported": true,
          "dry_run_parameter": "dry_run"
        }
      },
      "patch": {
        "tags": [
          "Keyword Lists"
        ],
        "summary": "Keyword lists: add or remove configured keywords.",
        "description": "Updates monitoring configuration; the request does not fetch fresh ranks.\n\nCost: 1 credit per update request\n\nBilling unit: `request`. Use `dry_run=true` to return an exact estimate before running the operation.",
        "operationId": "updateKeywordList",
        "parameters": [
          {
            "name": "dry_run",
            "in": "query",
            "description": "Set to true to return only the estimated usage and credits for this request. Dry-run requests do not execute the operation and do not debit the account balance.",
            "schema": {
              "type": "boolean"
            },
            "example": false
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateKeywordListRequest"
              },
              "example": {
                "project_id": "demo_project",
                "app_id": "6445911688",
                "country": "US",
                "platform": "ios",
                "add_keywords": [
                  "aso"
                ]
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateKeywordListRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateKeywordListRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/KeywordListMutationResponse"
                }
              }
            }
          },
          "400": {
            "description": "Validation failed. Body is ValidationProblemDetails."
          },
          "401": {
            "description": "Missing or invalid X-API-Key. Body is ProblemDetails with error_code=unauthorized."
          },
          "402": {
            "description": "Developer account credits are insufficient. Body is ProblemDetails with error_code=insufficient_credits."
          },
          "403": {
            "description": "Operation or data scope is not allowed. Body is ProblemDetails with error_code."
          },
          "429": {
            "description": "API key rate limit, dry-run rate limit, no-data rate guard, operation quota, or API key monthly credit limit exceeded. Rate-limit, no-data, and operation-quota responses include Retry-After and identify the exact quota. no_data_rate_limit_exceeded also includes the block reason, unlock time, and evaluated ratio.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the exhausted window resets or the temporary key block expires.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicApiRateLimitProblemDetails"
                },
                "examples": {
                  "minute_limit": {
                    "summary": "API key minute limit exceeded",
                    "value": {
                      "type": "https://developer.aso.dev/errors/operation_quota_exceeded",
                      "title": "Too Many Requests",
                      "status": 429,
                      "detail": "Public API key rate limit exceeded: 120 requests per minute.",
                      "error_code": "operation_quota_exceeded",
                      "request_id": "req_01JEXAMPLE",
                      "quota_scope": "api",
                      "quota_limit_type": "minute",
                      "quota_limit": 120,
                      "quota_window_seconds": 60
                    }
                  },
                  "no_data_block": {
                    "summary": "API key temporarily blocked by the no-data guard",
                    "value": {
                      "type": "https://developer.aso.dev/errors/no_data_rate_limit_exceeded",
                      "title": "Too Many Requests",
                      "status": 429,
                      "detail": "Public API key is temporarily blocked until 2026-07-30T15:05:00.0000000+00:00: no_data rate 81.09% (163 of 201 data requests) exceeded 80% after more than 200 requests in the trailing 900 seconds.",
                      "error_code": "no_data_rate_limit_exceeded",
                      "request_id": "req_01JEXAMPLE",
                      "quota_scope": "no_data",
                      "quota_limit_type": "ratio",
                      "quota_limit": 80,
                      "quota_window_seconds": 900,
                      "block_reason": "no_data_rate_exceeded",
                      "blocked_until_utc": "2026-07-30T15:05:00+00:00",
                      "evaluated_requests": 201,
                      "no_data_requests": 163,
                      "no_data_rate_percent": 81.09
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "An unexpected server-side failure occurred. Body is ProblemDetails with error_code=internal_server_error and the request_id used for support correlation.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "internal_server_error": {
                    "summary": "Unexpected server-side failure",
                    "value": {
                      "type": "https://developer.aso.dev/errors/internal_server_error",
                      "title": "Internal server error",
                      "status": 500,
                      "detail": "An unexpected error occurred while processing the request.",
                      "error_code": "internal_server_error",
                      "request_id": "req_01JEXAMPLE"
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "Credit ledger or request-accounting storage is temporarily unavailable. Body is ProblemDetails with error_code=credit_ledger_unavailable or public_api_storage_unavailable."
          }
        },
        "security": [
          {
            "ApiKeyAuth": [ ]
          }
        ],
        "x-aso-pricing": {
          "currency": "credits",
          "billing_unit": "request",
          "cost": "1 credit per update request",
          "formula": "1",
          "minimum_credits": 1,
          "dry_run_supported": true,
          "dry_run_parameter": "dry_run"
        }
      }
    },
    "/v1/keyword-lists/{tracking_id}": {
      "delete": {
        "tags": [
          "Keyword Lists"
        ],
        "summary": "Keyword lists: delete one keyword entry.",
        "description": "The delete is idempotent.\n\nCost: 1 credit per successful request\n\nBilling unit: `request`. Use `dry_run=true` to return an exact estimate before running the operation.",
        "operationId": "deleteKeywordListEntry",
        "parameters": [
          {
            "name": "tracking_id",
            "in": "path",
            "description": "Tracking id to delete. Required.",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "demo_tracking"
          },
          {
            "name": "dry_run",
            "in": "query",
            "description": "Set to true to return only the estimated usage and credits for this request. Dry-run requests do not execute the operation and do not debit the account balance.",
            "schema": {
              "type": "boolean"
            },
            "example": false
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DeleteKeywordListEntryResponse"
                }
              }
            }
          },
          "400": {
            "description": "Validation failed. Body is ValidationProblemDetails."
          },
          "401": {
            "description": "Missing or invalid X-API-Key. Body is ProblemDetails with error_code=unauthorized."
          },
          "402": {
            "description": "Developer account credits are insufficient. Body is ProblemDetails with error_code=insufficient_credits."
          },
          "403": {
            "description": "Operation or data scope is not allowed. Body is ProblemDetails with error_code."
          },
          "429": {
            "description": "API key rate limit, dry-run rate limit, no-data rate guard, operation quota, or API key monthly credit limit exceeded. Rate-limit, no-data, and operation-quota responses include Retry-After and identify the exact quota. no_data_rate_limit_exceeded also includes the block reason, unlock time, and evaluated ratio.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the exhausted window resets or the temporary key block expires.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicApiRateLimitProblemDetails"
                },
                "examples": {
                  "minute_limit": {
                    "summary": "API key minute limit exceeded",
                    "value": {
                      "type": "https://developer.aso.dev/errors/operation_quota_exceeded",
                      "title": "Too Many Requests",
                      "status": 429,
                      "detail": "Public API key rate limit exceeded: 120 requests per minute.",
                      "error_code": "operation_quota_exceeded",
                      "request_id": "req_01JEXAMPLE",
                      "quota_scope": "api",
                      "quota_limit_type": "minute",
                      "quota_limit": 120,
                      "quota_window_seconds": 60
                    }
                  },
                  "no_data_block": {
                    "summary": "API key temporarily blocked by the no-data guard",
                    "value": {
                      "type": "https://developer.aso.dev/errors/no_data_rate_limit_exceeded",
                      "title": "Too Many Requests",
                      "status": 429,
                      "detail": "Public API key is temporarily blocked until 2026-07-30T15:05:00.0000000+00:00: no_data rate 81.09% (163 of 201 data requests) exceeded 80% after more than 200 requests in the trailing 900 seconds.",
                      "error_code": "no_data_rate_limit_exceeded",
                      "request_id": "req_01JEXAMPLE",
                      "quota_scope": "no_data",
                      "quota_limit_type": "ratio",
                      "quota_limit": 80,
                      "quota_window_seconds": 900,
                      "block_reason": "no_data_rate_exceeded",
                      "blocked_until_utc": "2026-07-30T15:05:00+00:00",
                      "evaluated_requests": 201,
                      "no_data_requests": 163,
                      "no_data_rate_percent": 81.09
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "An unexpected server-side failure occurred. Body is ProblemDetails with error_code=internal_server_error and the request_id used for support correlation.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "internal_server_error": {
                    "summary": "Unexpected server-side failure",
                    "value": {
                      "type": "https://developer.aso.dev/errors/internal_server_error",
                      "title": "Internal server error",
                      "status": 500,
                      "detail": "An unexpected error occurred while processing the request.",
                      "error_code": "internal_server_error",
                      "request_id": "req_01JEXAMPLE"
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "Credit ledger or request-accounting storage is temporarily unavailable. Body is ProblemDetails with error_code=credit_ledger_unavailable or public_api_storage_unavailable."
          }
        },
        "security": [
          {
            "ApiKeyAuth": [ ]
          }
        ],
        "x-aso-pricing": {
          "currency": "credits",
          "billing_unit": "request",
          "cost": "1 credit per successful request",
          "formula": "1",
          "minimum_credits": 1,
          "dry_run_supported": true,
          "dry_run_parameter": "dry_run"
        }
      }
    },
    "/v1/keywords/metrics/popularity/latest": {
      "get": {
        "tags": [
          "Keyword Metrics"
        ],
        "summary": "Keyword metrics: latest App Store search popularity.",
        "description": "Returns the latest stored Apple search popularity for a keyword and country.\n\nCost: 6 credits\n\nBilling unit: `keyword_country_platform`. Use `dry_run=true` to return an exact estimate before running the operation.",
        "operationId": "getKeywordPopularityMetricsLatest",
        "parameters": [
          {
            "name": "term",
            "in": "query",
            "description": "Keyword term to look up. Required, normalized maximum length is 200 characters.",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "aso"
          },
          {
            "name": "country",
            "in": "query",
            "description": "Two-letter App Store country code. Required.",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "US"
          },
          {
            "name": "dry_run",
            "in": "query",
            "description": "Set to true to return only the estimated usage and credits for this request. Dry-run requests do not execute the operation and do not debit the account balance.",
            "schema": {
              "type": "boolean"
            },
            "example": false
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/KeywordPopularityMetricsResponse"
                }
              }
            }
          },
          "400": {
            "description": "Validation failed. Body is ValidationProblemDetails."
          },
          "401": {
            "description": "Missing or invalid X-API-Key. Body is ProblemDetails with error_code=unauthorized."
          },
          "402": {
            "description": "Developer account credits are insufficient. Body is ProblemDetails with error_code=insufficient_credits."
          },
          "403": {
            "description": "Operation or data scope is not allowed. Body is ProblemDetails with error_code."
          },
          "429": {
            "description": "API key rate limit, dry-run rate limit, no-data rate guard, operation quota, or API key monthly credit limit exceeded. Rate-limit, no-data, and operation-quota responses include Retry-After and identify the exact quota. no_data_rate_limit_exceeded also includes the block reason, unlock time, and evaluated ratio.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the exhausted window resets or the temporary key block expires.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicApiRateLimitProblemDetails"
                },
                "examples": {
                  "minute_limit": {
                    "summary": "API key minute limit exceeded",
                    "value": {
                      "type": "https://developer.aso.dev/errors/operation_quota_exceeded",
                      "title": "Too Many Requests",
                      "status": 429,
                      "detail": "Public API key rate limit exceeded: 120 requests per minute.",
                      "error_code": "operation_quota_exceeded",
                      "request_id": "req_01JEXAMPLE",
                      "quota_scope": "api",
                      "quota_limit_type": "minute",
                      "quota_limit": 120,
                      "quota_window_seconds": 60
                    }
                  },
                  "no_data_block": {
                    "summary": "API key temporarily blocked by the no-data guard",
                    "value": {
                      "type": "https://developer.aso.dev/errors/no_data_rate_limit_exceeded",
                      "title": "Too Many Requests",
                      "status": 429,
                      "detail": "Public API key is temporarily blocked until 2026-07-30T15:05:00.0000000+00:00: no_data rate 81.09% (163 of 201 data requests) exceeded 80% after more than 200 requests in the trailing 900 seconds.",
                      "error_code": "no_data_rate_limit_exceeded",
                      "request_id": "req_01JEXAMPLE",
                      "quota_scope": "no_data",
                      "quota_limit_type": "ratio",
                      "quota_limit": 80,
                      "quota_window_seconds": 900,
                      "block_reason": "no_data_rate_exceeded",
                      "blocked_until_utc": "2026-07-30T15:05:00+00:00",
                      "evaluated_requests": 201,
                      "no_data_requests": 163,
                      "no_data_rate_percent": 81.09
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "An unexpected server-side failure occurred. Body is ProblemDetails with error_code=internal_server_error and the request_id used for support correlation.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "internal_server_error": {
                    "summary": "Unexpected server-side failure",
                    "value": {
                      "type": "https://developer.aso.dev/errors/internal_server_error",
                      "title": "Internal server error",
                      "status": 500,
                      "detail": "An unexpected error occurred while processing the request.",
                      "error_code": "internal_server_error",
                      "request_id": "req_01JEXAMPLE"
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "Credit ledger or request-accounting storage is temporarily unavailable. Body is ProblemDetails with error_code=credit_ledger_unavailable or public_api_storage_unavailable."
          }
        },
        "security": [
          {
            "ApiKeyAuth": [ ]
          }
        ],
        "x-aso-pricing": {
          "currency": "credits",
          "billing_unit": "keyword_country_platform",
          "cost": "6 credits",
          "formula": "6",
          "minimum_credits": 6,
          "dry_run_supported": true,
          "dry_run_parameter": "dry_run"
        }
      }
    },
    "/v1/keywords/metrics/popularity/average": {
      "get": {
        "tags": [
          "Keyword Metrics"
        ],
        "summary": "Keyword metrics: average App Store search popularity since September 1, 2025.",
        "description": "The average excludes popularity values equal to 5 recorded on or after\nSeptember 29, 2025, when Apple changed the Search Ads Popularity data distribution.\n[Read the ASO.dev analysis](https://aso.dev/blog/apple-ads-popularity-massive-drop/).\n\nCost: 60 credits\n\nBilling unit: `keyword_country_platform`. Use `dry_run=true` to return an exact estimate before running the operation.",
        "operationId": "getKeywordPopularityMetricsAverage",
        "parameters": [
          {
            "name": "term",
            "in": "query",
            "description": "Keyword term to look up. Required, normalized maximum length is 200 characters.",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "aso"
          },
          {
            "name": "country",
            "in": "query",
            "description": "Two-letter App Store country code. Required.",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "US"
          },
          {
            "name": "dry_run",
            "in": "query",
            "description": "Set to true to return only the estimated usage and credits for this request. Dry-run requests do not execute the operation and do not debit the account balance.",
            "schema": {
              "type": "boolean"
            },
            "example": false
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/KeywordPopularityMetricsResponse"
                }
              }
            }
          },
          "400": {
            "description": "Validation failed. Body is ValidationProblemDetails."
          },
          "401": {
            "description": "Missing or invalid X-API-Key. Body is ProblemDetails with error_code=unauthorized."
          },
          "402": {
            "description": "Developer account credits are insufficient. Body is ProblemDetails with error_code=insufficient_credits."
          },
          "403": {
            "description": "Operation or data scope is not allowed. Body is ProblemDetails with error_code."
          },
          "429": {
            "description": "API key rate limit, dry-run rate limit, no-data rate guard, operation quota, or API key monthly credit limit exceeded. Rate-limit, no-data, and operation-quota responses include Retry-After and identify the exact quota. no_data_rate_limit_exceeded also includes the block reason, unlock time, and evaluated ratio.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the exhausted window resets or the temporary key block expires.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicApiRateLimitProblemDetails"
                },
                "examples": {
                  "minute_limit": {
                    "summary": "API key minute limit exceeded",
                    "value": {
                      "type": "https://developer.aso.dev/errors/operation_quota_exceeded",
                      "title": "Too Many Requests",
                      "status": 429,
                      "detail": "Public API key rate limit exceeded: 120 requests per minute.",
                      "error_code": "operation_quota_exceeded",
                      "request_id": "req_01JEXAMPLE",
                      "quota_scope": "api",
                      "quota_limit_type": "minute",
                      "quota_limit": 120,
                      "quota_window_seconds": 60
                    }
                  },
                  "no_data_block": {
                    "summary": "API key temporarily blocked by the no-data guard",
                    "value": {
                      "type": "https://developer.aso.dev/errors/no_data_rate_limit_exceeded",
                      "title": "Too Many Requests",
                      "status": 429,
                      "detail": "Public API key is temporarily blocked until 2026-07-30T15:05:00.0000000+00:00: no_data rate 81.09% (163 of 201 data requests) exceeded 80% after more than 200 requests in the trailing 900 seconds.",
                      "error_code": "no_data_rate_limit_exceeded",
                      "request_id": "req_01JEXAMPLE",
                      "quota_scope": "no_data",
                      "quota_limit_type": "ratio",
                      "quota_limit": 80,
                      "quota_window_seconds": 900,
                      "block_reason": "no_data_rate_exceeded",
                      "blocked_until_utc": "2026-07-30T15:05:00+00:00",
                      "evaluated_requests": 201,
                      "no_data_requests": 163,
                      "no_data_rate_percent": 81.09
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "An unexpected server-side failure occurred. Body is ProblemDetails with error_code=internal_server_error and the request_id used for support correlation.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "internal_server_error": {
                    "summary": "Unexpected server-side failure",
                    "value": {
                      "type": "https://developer.aso.dev/errors/internal_server_error",
                      "title": "Internal server error",
                      "status": 500,
                      "detail": "An unexpected error occurred while processing the request.",
                      "error_code": "internal_server_error",
                      "request_id": "req_01JEXAMPLE"
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "Credit ledger or request-accounting storage is temporarily unavailable. Body is ProblemDetails with error_code=credit_ledger_unavailable or public_api_storage_unavailable."
          }
        },
        "security": [
          {
            "ApiKeyAuth": [ ]
          }
        ],
        "x-aso-pricing": {
          "currency": "credits",
          "billing_unit": "keyword_country_platform",
          "cost": "60 credits",
          "formula": "60",
          "minimum_credits": 60,
          "dry_run_supported": true,
          "dry_run_parameter": "dry_run"
        }
      }
    },
    "/v1/keywords/search-results/live": {
      "post": {
        "tags": [
          "Keyword Search Results"
        ],
        "summary": "Keyword search results: live Apple lookup.",
        "description": "Fetches Apple search results on demand for one keyword. Returns the selected app\nrank when app_id is provided, otherwise the organic result page.\n\nCost: 15 credits for a selected-app lookup or the full live SERP\n\nBilling unit: `app_keyword or full_serp`. Use `dry_run=true` to return an exact estimate before running the operation.",
        "operationId": "getLiveKeywordSearchResults",
        "parameters": [
          {
            "name": "dry_run",
            "in": "query",
            "description": "Set to true to return only the estimated usage and credits for this request. Dry-run requests do not execute the operation and do not debit the account balance.",
            "schema": {
              "type": "boolean"
            },
            "example": false
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/LiveKeywordSearchResultsRequest"
              },
              "example": {
                "app_id": "6445911688",
                "keyword": "aso",
                "country": "US",
                "platform": "ios"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/LiveKeywordSearchResultsRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/LiveKeywordSearchResultsRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/KeywordSearchResultsResponse"
                }
              }
            }
          },
          "400": {
            "description": "Validation failed. Body is ValidationProblemDetails."
          },
          "401": {
            "description": "Missing or invalid X-API-Key. Body is ProblemDetails with error_code=unauthorized."
          },
          "402": {
            "description": "Developer account credits are insufficient. Body is ProblemDetails with error_code=insufficient_credits."
          },
          "403": {
            "description": "Operation or data scope is not allowed. Body is ProblemDetails with error_code."
          },
          "429": {
            "description": "API key rate limit, dry-run rate limit, no-data rate guard, operation quota, or API key monthly credit limit exceeded. Rate-limit, no-data, and operation-quota responses include Retry-After and identify the exact quota. no_data_rate_limit_exceeded also includes the block reason, unlock time, and evaluated ratio.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the exhausted window resets or the temporary key block expires.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicApiRateLimitProblemDetails"
                },
                "examples": {
                  "minute_limit": {
                    "summary": "API key minute limit exceeded",
                    "value": {
                      "type": "https://developer.aso.dev/errors/operation_quota_exceeded",
                      "title": "Too Many Requests",
                      "status": 429,
                      "detail": "Public API key rate limit exceeded: 120 requests per minute.",
                      "error_code": "operation_quota_exceeded",
                      "request_id": "req_01JEXAMPLE",
                      "quota_scope": "api",
                      "quota_limit_type": "minute",
                      "quota_limit": 120,
                      "quota_window_seconds": 60
                    }
                  },
                  "no_data_block": {
                    "summary": "API key temporarily blocked by the no-data guard",
                    "value": {
                      "type": "https://developer.aso.dev/errors/no_data_rate_limit_exceeded",
                      "title": "Too Many Requests",
                      "status": 429,
                      "detail": "Public API key is temporarily blocked until 2026-07-30T15:05:00.0000000+00:00: no_data rate 81.09% (163 of 201 data requests) exceeded 80% after more than 200 requests in the trailing 900 seconds.",
                      "error_code": "no_data_rate_limit_exceeded",
                      "request_id": "req_01JEXAMPLE",
                      "quota_scope": "no_data",
                      "quota_limit_type": "ratio",
                      "quota_limit": 80,
                      "quota_window_seconds": 900,
                      "block_reason": "no_data_rate_exceeded",
                      "blocked_until_utc": "2026-07-30T15:05:00+00:00",
                      "evaluated_requests": 201,
                      "no_data_requests": 163,
                      "no_data_rate_percent": 81.09
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "An unexpected server-side failure occurred. Body is ProblemDetails with error_code=internal_server_error and the request_id used for support correlation.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "internal_server_error": {
                    "summary": "Unexpected server-side failure",
                    "value": {
                      "type": "https://developer.aso.dev/errors/internal_server_error",
                      "title": "Internal server error",
                      "status": 500,
                      "detail": "An unexpected error occurred while processing the request.",
                      "error_code": "internal_server_error",
                      "request_id": "req_01JEXAMPLE"
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "Credit ledger or request-accounting storage is temporarily unavailable. Body is ProblemDetails with error_code=credit_ledger_unavailable or public_api_storage_unavailable."
          }
        },
        "security": [
          {
            "ApiKeyAuth": [ ]
          }
        ],
        "x-aso-pricing": {
          "currency": "credits",
          "billing_unit": "app_keyword or full_serp",
          "cost": "15 credits for a selected-app lookup or the full live SERP",
          "formula": "15",
          "minimum_credits": 15,
          "dry_run_supported": true,
          "dry_run_parameter": "dry_run"
        }
      }
    },
    "/v1/keywords/search-results/collected": {
      "post": {
        "tags": [
          "Keyword Search Results"
        ],
        "summary": "Keyword search results: collected top apps.",
        "description": "Reads the latest collected search results for each keyword from a separate stored\ncollection. Returns up to 10 organic apps per keyword, with last_updated and snapshot\npagination. This operation does not fetch Apple on demand. Use\nPOST /v1/keywords/search-results/live for a direct Apple lookup. The optional app_id\naffects access scope only, not the returned apps.\n\nCost: 3 * max(1, ceil(keyword_count * limit / 10)) credits; offset snapshot pages cost 3 credits\n\nBilling unit: `keyword_app`. Use `dry_run=true` to return an exact estimate before running the operation.",
        "operationId": "getCollectedKeywordSearchResults",
        "parameters": [
          {
            "name": "dry_run",
            "in": "query",
            "description": "Set to true to return only the estimated usage and credits for this request. Dry-run requests do not execute the operation and do not debit the account balance.",
            "schema": {
              "type": "boolean"
            },
            "example": false
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CollectedKeywordSearchResultsRequest"
              },
              "example": {
                "app_id": "6445911688",
                "country": "US",
                "platform": "ios",
                "keywords": [
                  "aso"
                ],
                "limit": 10,
                "offset": 0
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/CollectedKeywordSearchResultsRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/CollectedKeywordSearchResultsRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CollectedKeywordSearchResultsResponse"
                }
              }
            }
          },
          "400": {
            "description": "Validation failed. Body is ValidationProblemDetails."
          },
          "401": {
            "description": "Missing or invalid X-API-Key. Body is ProblemDetails with error_code=unauthorized."
          },
          "402": {
            "description": "Developer account credits are insufficient. Body is ProblemDetails with error_code=insufficient_credits."
          },
          "403": {
            "description": "Operation or data scope is not allowed. Body is ProblemDetails with error_code."
          },
          "429": {
            "description": "API key rate limit, dry-run rate limit, no-data rate guard, operation quota, or API key monthly credit limit exceeded. Rate-limit, no-data, and operation-quota responses include Retry-After and identify the exact quota. no_data_rate_limit_exceeded also includes the block reason, unlock time, and evaluated ratio.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the exhausted window resets or the temporary key block expires.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicApiRateLimitProblemDetails"
                },
                "examples": {
                  "minute_limit": {
                    "summary": "API key minute limit exceeded",
                    "value": {
                      "type": "https://developer.aso.dev/errors/operation_quota_exceeded",
                      "title": "Too Many Requests",
                      "status": 429,
                      "detail": "Public API key rate limit exceeded: 120 requests per minute.",
                      "error_code": "operation_quota_exceeded",
                      "request_id": "req_01JEXAMPLE",
                      "quota_scope": "api",
                      "quota_limit_type": "minute",
                      "quota_limit": 120,
                      "quota_window_seconds": 60
                    }
                  },
                  "no_data_block": {
                    "summary": "API key temporarily blocked by the no-data guard",
                    "value": {
                      "type": "https://developer.aso.dev/errors/no_data_rate_limit_exceeded",
                      "title": "Too Many Requests",
                      "status": 429,
                      "detail": "Public API key is temporarily blocked until 2026-07-30T15:05:00.0000000+00:00: no_data rate 81.09% (163 of 201 data requests) exceeded 80% after more than 200 requests in the trailing 900 seconds.",
                      "error_code": "no_data_rate_limit_exceeded",
                      "request_id": "req_01JEXAMPLE",
                      "quota_scope": "no_data",
                      "quota_limit_type": "ratio",
                      "quota_limit": 80,
                      "quota_window_seconds": 900,
                      "block_reason": "no_data_rate_exceeded",
                      "blocked_until_utc": "2026-07-30T15:05:00+00:00",
                      "evaluated_requests": 201,
                      "no_data_requests": 163,
                      "no_data_rate_percent": 81.09
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "An unexpected server-side failure occurred. Body is ProblemDetails with error_code=internal_server_error and the request_id used for support correlation.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "internal_server_error": {
                    "summary": "Unexpected server-side failure",
                    "value": {
                      "type": "https://developer.aso.dev/errors/internal_server_error",
                      "title": "Internal server error",
                      "status": 500,
                      "detail": "An unexpected error occurred while processing the request.",
                      "error_code": "internal_server_error",
                      "request_id": "req_01JEXAMPLE"
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "Credit ledger or request-accounting storage is temporarily unavailable. Body is ProblemDetails with error_code=credit_ledger_unavailable or public_api_storage_unavailable."
          }
        },
        "security": [
          {
            "ApiKeyAuth": [ ]
          }
        ],
        "x-aso-pricing": {
          "currency": "credits",
          "billing_unit": "keyword_app",
          "cost": "3 * max(1, ceil(keyword_count * limit / 10)) credits; offset snapshot pages cost 3 credits",
          "formula": "3 * max(1, ceil(keyword_count * limit / 10))",
          "minimum_credits": 3,
          "dry_run_supported": true,
          "dry_run_parameter": "dry_run"
        }
      }
    },
    "/v1/keywords/search-results/latest": {
      "post": {
        "tags": [
          "Keyword Search Results"
        ],
        "summary": "Keyword search results: latest stored results.",
        "description": "Reads the latest available search observation from today's or yesterday's stored\nranking data. Returns up to 200 organic app results, or the selected app rank when\napp_id is provided. This stored source differs from collected top-app results at\nPOST /v1/keywords/search-results/collected. Use POST /v1/keywords/search-results/live for a direct Apple lookup.\n\nCost: 3 credits\n\nBilling unit: `keyword_search`. Use `dry_run=true` to return an exact estimate before running the operation.",
        "operationId": "getLatestKeywordSearchResults",
        "parameters": [
          {
            "name": "dry_run",
            "in": "query",
            "description": "Set to true to return only the estimated usage and credits for this request. Dry-run requests do not execute the operation and do not debit the account balance.",
            "schema": {
              "type": "boolean"
            },
            "example": false
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/LatestKeywordSearchResultsRequest"
              },
              "example": {
                "app_id": "6445911688",
                "keyword": "aso",
                "country": "US",
                "platform": "ios"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/LatestKeywordSearchResultsRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/LatestKeywordSearchResultsRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/KeywordSearchResultsResponse"
                }
              }
            }
          },
          "400": {
            "description": "Validation failed. Body is ValidationProblemDetails."
          },
          "401": {
            "description": "Missing or invalid X-API-Key. Body is ProblemDetails with error_code=unauthorized."
          },
          "402": {
            "description": "Developer account credits are insufficient. Body is ProblemDetails with error_code=insufficient_credits."
          },
          "403": {
            "description": "Operation or data scope is not allowed. Body is ProblemDetails with error_code."
          },
          "429": {
            "description": "API key rate limit, dry-run rate limit, no-data rate guard, operation quota, or API key monthly credit limit exceeded. Rate-limit, no-data, and operation-quota responses include Retry-After and identify the exact quota. no_data_rate_limit_exceeded also includes the block reason, unlock time, and evaluated ratio.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the exhausted window resets or the temporary key block expires.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicApiRateLimitProblemDetails"
                },
                "examples": {
                  "minute_limit": {
                    "summary": "API key minute limit exceeded",
                    "value": {
                      "type": "https://developer.aso.dev/errors/operation_quota_exceeded",
                      "title": "Too Many Requests",
                      "status": 429,
                      "detail": "Public API key rate limit exceeded: 120 requests per minute.",
                      "error_code": "operation_quota_exceeded",
                      "request_id": "req_01JEXAMPLE",
                      "quota_scope": "api",
                      "quota_limit_type": "minute",
                      "quota_limit": 120,
                      "quota_window_seconds": 60
                    }
                  },
                  "no_data_block": {
                    "summary": "API key temporarily blocked by the no-data guard",
                    "value": {
                      "type": "https://developer.aso.dev/errors/no_data_rate_limit_exceeded",
                      "title": "Too Many Requests",
                      "status": 429,
                      "detail": "Public API key is temporarily blocked until 2026-07-30T15:05:00.0000000+00:00: no_data rate 81.09% (163 of 201 data requests) exceeded 80% after more than 200 requests in the trailing 900 seconds.",
                      "error_code": "no_data_rate_limit_exceeded",
                      "request_id": "req_01JEXAMPLE",
                      "quota_scope": "no_data",
                      "quota_limit_type": "ratio",
                      "quota_limit": 80,
                      "quota_window_seconds": 900,
                      "block_reason": "no_data_rate_exceeded",
                      "blocked_until_utc": "2026-07-30T15:05:00+00:00",
                      "evaluated_requests": 201,
                      "no_data_requests": 163,
                      "no_data_rate_percent": 81.09
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "An unexpected server-side failure occurred. Body is ProblemDetails with error_code=internal_server_error and the request_id used for support correlation.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "internal_server_error": {
                    "summary": "Unexpected server-side failure",
                    "value": {
                      "type": "https://developer.aso.dev/errors/internal_server_error",
                      "title": "Internal server error",
                      "status": 500,
                      "detail": "An unexpected error occurred while processing the request.",
                      "error_code": "internal_server_error",
                      "request_id": "req_01JEXAMPLE"
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "Credit ledger or request-accounting storage is temporarily unavailable. Body is ProblemDetails with error_code=credit_ledger_unavailable or public_api_storage_unavailable."
          }
        },
        "security": [
          {
            "ApiKeyAuth": [ ]
          }
        ],
        "x-aso-pricing": {
          "currency": "credits",
          "billing_unit": "keyword_search",
          "cost": "3 credits",
          "formula": "3",
          "minimum_credits": 3,
          "dry_run_supported": true,
          "dry_run_parameter": "dry_run"
        }
      }
    },
    "/v1/projects": {
      "get": {
        "tags": [
          "Projects"
        ],
        "summary": "Returns active ASO.dev projects for the user email attached to the authenticated API key.",
        "description": "Cost: 1 credit per successful request\n\nBilling unit: `request`. Use `dry_run=true` to return an exact estimate before running the operation.",
        "operationId": "getProjects",
        "parameters": [
          {
            "name": "dry_run",
            "in": "query",
            "description": "Set to true to return only the estimated usage and credits for this request. Dry-run requests do not execute the operation and do not debit the account balance.",
            "schema": {
              "type": "boolean"
            },
            "example": false
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProjectsListResponse"
                }
              }
            }
          },
          "400": {
            "description": "Validation failed. Body is ValidationProblemDetails."
          },
          "401": {
            "description": "Missing or invalid X-API-Key. Body is ProblemDetails with error_code=unauthorized."
          },
          "402": {
            "description": "Developer account credits are insufficient. Body is ProblemDetails with error_code=insufficient_credits."
          },
          "403": {
            "description": "Operation or data scope is not allowed. Body is ProblemDetails with error_code."
          },
          "429": {
            "description": "API key rate limit, dry-run rate limit, no-data rate guard, operation quota, or API key monthly credit limit exceeded. Rate-limit, no-data, and operation-quota responses include Retry-After and identify the exact quota. no_data_rate_limit_exceeded also includes the block reason, unlock time, and evaluated ratio.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the exhausted window resets or the temporary key block expires.",
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicApiRateLimitProblemDetails"
                },
                "examples": {
                  "minute_limit": {
                    "summary": "API key minute limit exceeded",
                    "value": {
                      "type": "https://developer.aso.dev/errors/operation_quota_exceeded",
                      "title": "Too Many Requests",
                      "status": 429,
                      "detail": "Public API key rate limit exceeded: 120 requests per minute.",
                      "error_code": "operation_quota_exceeded",
                      "request_id": "req_01JEXAMPLE",
                      "quota_scope": "api",
                      "quota_limit_type": "minute",
                      "quota_limit": 120,
                      "quota_window_seconds": 60
                    }
                  },
                  "no_data_block": {
                    "summary": "API key temporarily blocked by the no-data guard",
                    "value": {
                      "type": "https://developer.aso.dev/errors/no_data_rate_limit_exceeded",
                      "title": "Too Many Requests",
                      "status": 429,
                      "detail": "Public API key is temporarily blocked until 2026-07-30T15:05:00.0000000+00:00: no_data rate 81.09% (163 of 201 data requests) exceeded 80% after more than 200 requests in the trailing 900 seconds.",
                      "error_code": "no_data_rate_limit_exceeded",
                      "request_id": "req_01JEXAMPLE",
                      "quota_scope": "no_data",
                      "quota_limit_type": "ratio",
                      "quota_limit": 80,
                      "quota_window_seconds": 900,
                      "block_reason": "no_data_rate_exceeded",
                      "blocked_until_utc": "2026-07-30T15:05:00+00:00",
                      "evaluated_requests": 201,
                      "no_data_requests": 163,
                      "no_data_rate_percent": 81.09
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "An unexpected server-side failure occurred. Body is ProblemDetails with error_code=internal_server_error and the request_id used for support correlation.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "internal_server_error": {
                    "summary": "Unexpected server-side failure",
                    "value": {
                      "type": "https://developer.aso.dev/errors/internal_server_error",
                      "title": "Internal server error",
                      "status": 500,
                      "detail": "An unexpected error occurred while processing the request.",
                      "error_code": "internal_server_error",
                      "request_id": "req_01JEXAMPLE"
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "Credit ledger or request-accounting storage is temporarily unavailable. Body is ProblemDetails with error_code=credit_ledger_unavailable or public_api_storage_unavailable."
          }
        },
        "security": [
          {
            "ApiKeyAuth": [ ]
          }
        ],
        "x-aso-pricing": {
          "currency": "credits",
          "billing_unit": "request",
          "cost": "1 credit per successful request",
          "formula": "1",
          "minimum_credits": 1,
          "dry_run_supported": true,
          "dry_run_parameter": "dry_run"
        }
      }
    }
  },
  "components": {
    "schemas": {
      "AppChartAppMeta": {
        "type": "object",
        "properties": {
          "app_id": {
            "type": "string",
            "nullable": true
          },
          "url": {
            "type": "string",
            "description": "Public App Store product page URL.",
            "nullable": true
          },
          "icon_url": {
            "type": "string",
            "nullable": true
          },
          "rating": {
            "type": "number",
            "description": "Average App Store user rating.",
            "format": "double",
            "nullable": true
          },
          "primary_genre": {
            "$ref": "#/components/schemas/AppSummaryGenre"
          },
          "secondary_genres": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AppSummaryGenre"
            },
            "nullable": true
          },
          "title": {
            "type": "string",
            "nullable": true
          },
          "subtitle": {
            "type": "string",
            "nullable": true
          },
          "description": {
            "type": "string",
            "nullable": true
          },
          "bundle_id": {
            "type": "string",
            "nullable": true
          },
          "rating_count": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "rating_count_list": {
            "type": "array",
            "items": {
              "type": "integer",
              "format": "int32"
            },
            "nullable": true
          },
          "release_date": {
            "type": "string",
            "format": "date",
            "nullable": true
          },
          "developer_name": {
            "type": "string",
            "nullable": true
          },
          "version": {
            "type": "string",
            "nullable": true
          },
          "price": {
            "type": "string",
            "nullable": true
          },
          "has_in_app_purchases": {
            "type": "boolean",
            "nullable": true
          },
          "in_app_purchases": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AppChartInAppPurchase"
            },
            "nullable": true
          },
          "age_rating": {
            "type": "string",
            "nullable": true
          },
          "website": {
            "type": "string",
            "nullable": true
          },
          "support_url": {
            "type": "string",
            "nullable": true
          },
          "privacy_policy_url": {
            "type": "string",
            "nullable": true
          },
          "copyright": {
            "type": "string",
            "nullable": true
          },
          "date_check_utc": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "AppChartHourlyRequest": {
        "required": [
          "category_id",
          "country",
          "platform",
          "type"
        ],
        "type": "object",
        "properties": {
          "country": {
            "minLength": 1,
            "type": "string",
            "description": "Supported two-letter App Store country code."
          },
          "lang": {
            "type": "string",
            "description": "Optional Apple language tag. It is sent to Apple for live charts and metadata enrichment; stored chart positions are country-scoped.",
            "nullable": true
          },
          "platform": {
            "$ref": "#/components/schemas/AppRankingPlatform"
          },
          "type": {
            "$ref": "#/components/schemas/AppRankingType"
          },
          "category_id": {
            "type": "integer",
            "description": "App Store category id. Use GET /v1/dictionaries/app-categories.",
            "format": "int32"
          },
          "limit": {
            "maximum": 500,
            "minimum": 1,
            "type": "integer",
            "description": "Maximum number of chart rows returned. Default is 500, maximum is 500.",
            "format": "int32",
            "default": 500,
            "nullable": true
          },
          "offset": {
            "maximum": 2147483647,
            "minimum": 0,
            "type": "integer",
            "description": "Number of chart rows to skip.",
            "format": "int32",
            "default": 0,
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "AppChartHourlyResponse": {
        "required": [
          "meta"
        ],
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AppChartItem"
            },
            "nullable": true
          },
          "snapshot_at_utc": {
            "type": "string",
            "description": "UTC collection timestamp of the requested chart, no older than one hour.\nMissing or expired snapshots are refreshed live and saved. Null when Apple returns no apps.\nIt remains available when pagination returns no rows.",
            "format": "date-time",
            "nullable": true
          },
          "meta": {
            "$ref": "#/components/schemas/ResponseMeta"
          }
        },
        "additionalProperties": false
      },
      "AppChartInAppPurchase": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "nullable": true
          },
          "name": {
            "type": "string",
            "nullable": true
          },
          "price": {
            "type": "string",
            "nullable": true
          },
          "currency": {
            "type": "string",
            "nullable": true
          },
          "is_subscription": {
            "type": "boolean",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "AppChartIncluded": {
        "type": "object",
        "properties": {
          "app_meta": {
            "type": "object",
            "additionalProperties": {
              "$ref": "#/components/schemas/AppChartAppMeta"
            },
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "AppChartItem": {
        "required": [
          "app_id",
          "category",
          "category_id",
          "country",
          "date",
          "platform",
          "rank",
          "type"
        ],
        "type": "object",
        "properties": {
          "app_id": {
            "type": "string",
            "nullable": true
          },
          "country": {
            "type": "string",
            "nullable": true
          },
          "date": {
            "type": "string",
            "format": "date"
          },
          "platform": {
            "$ref": "#/components/schemas/AppRankingPlatform"
          },
          "type": {
            "$ref": "#/components/schemas/AppRankingType"
          },
          "category_id": {
            "type": "integer",
            "format": "int32"
          },
          "category": {
            "type": "string",
            "nullable": true
          },
          "rank": {
            "type": "integer",
            "format": "int32"
          }
        },
        "additionalProperties": false
      },
      "AppChartLiveRequest": {
        "required": [
          "category_id",
          "country",
          "platform",
          "type"
        ],
        "type": "object",
        "properties": {
          "country": {
            "minLength": 1,
            "type": "string",
            "description": "Supported two-letter App Store country code."
          },
          "lang": {
            "type": "string",
            "description": "Optional Apple language tag. It is sent to Apple for live charts and metadata enrichment; stored chart positions are country-scoped.",
            "nullable": true
          },
          "platform": {
            "$ref": "#/components/schemas/AppRankingPlatform"
          },
          "type": {
            "$ref": "#/components/schemas/AppRankingType"
          },
          "category_id": {
            "type": "integer",
            "description": "App Store category id. Use GET /v1/dictionaries/app-categories.",
            "format": "int32"
          },
          "limit": {
            "maximum": 500,
            "minimum": 1,
            "type": "integer",
            "description": "Maximum number of chart rows returned. Default is 500, maximum is 500.",
            "format": "int32",
            "default": 500,
            "nullable": true
          },
          "offset": {
            "maximum": 2147483647,
            "minimum": 0,
            "type": "integer",
            "description": "Number of chart rows to skip.",
            "format": "int32",
            "default": 0,
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "AppChartQueryRequest": {
        "required": [
          "category_id",
          "country",
          "platform",
          "type"
        ],
        "type": "object",
        "properties": {
          "country": {
            "minLength": 1,
            "type": "string",
            "description": "Supported two-letter App Store country code."
          },
          "lang": {
            "type": "string",
            "description": "Optional Apple language tag. It is sent to Apple for live charts and metadata enrichment; stored chart positions are country-scoped.",
            "nullable": true
          },
          "platform": {
            "$ref": "#/components/schemas/AppRankingPlatform"
          },
          "type": {
            "$ref": "#/components/schemas/AppRankingType"
          },
          "category_id": {
            "type": "integer",
            "description": "App Store category id. Use GET /v1/dictionaries/app-categories.",
            "format": "int32"
          },
          "limit": {
            "maximum": 500,
            "minimum": 1,
            "type": "integer",
            "description": "Maximum number of chart rows returned. Default is 500, maximum is 500.",
            "format": "int32",
            "default": 500,
            "nullable": true
          },
          "offset": {
            "maximum": 2147483647,
            "minimum": 0,
            "type": "integer",
            "description": "Number of chart rows to skip.",
            "format": "int32",
            "default": 0,
            "nullable": true
          },
          "date": {
            "type": "string",
            "description": "Daily ranking snapshot date. When omitted, the latest available daily snapshot is returned. Earliest supported date is 2024-09-15.",
            "format": "date",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "AppChartQueryResponse": {
        "required": [
          "meta"
        ],
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AppChartItem"
            },
            "nullable": true
          },
          "meta": {
            "$ref": "#/components/schemas/ResponseMeta"
          }
        },
        "additionalProperties": false
      },
      "AppChartWithMetaQueryRequest": {
        "required": [
          "category_id",
          "country",
          "platform",
          "type"
        ],
        "type": "object",
        "properties": {
          "country": {
            "minLength": 1,
            "type": "string",
            "description": "Supported two-letter App Store country code."
          },
          "lang": {
            "type": "string",
            "description": "Optional Apple language tag. It is sent to Apple for live charts and metadata enrichment; stored chart positions are country-scoped.",
            "nullable": true
          },
          "platform": {
            "$ref": "#/components/schemas/AppRankingPlatform"
          },
          "type": {
            "$ref": "#/components/schemas/AppRankingType"
          },
          "category_id": {
            "type": "integer",
            "description": "App Store category id. Use GET /v1/dictionaries/app-categories.",
            "format": "int32"
          },
          "limit": {
            "maximum": 500,
            "minimum": 1,
            "type": "integer",
            "description": "Maximum number of chart rows returned. Default is 500, maximum is 500.",
            "format": "int32",
            "default": 500,
            "nullable": true
          },
          "offset": {
            "maximum": 2147483647,
            "minimum": 0,
            "type": "integer",
            "description": "Number of chart rows to skip.",
            "format": "int32",
            "default": 0,
            "nullable": true
          },
          "date": {
            "type": "string",
            "description": "Daily ranking snapshot date. When omitted, the latest available daily snapshot is returned. Earliest supported date is 2024-09-15.",
            "format": "date",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "AppChartWithMetaQueryResponse": {
        "required": [
          "included",
          "meta"
        ],
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AppChartItem"
            },
            "nullable": true
          },
          "included": {
            "$ref": "#/components/schemas/AppChartIncluded"
          },
          "meta": {
            "$ref": "#/components/schemas/ResponseMeta"
          }
        },
        "additionalProperties": false
      },
      "AppDetailsLiveRequest": {
        "required": [
          "app_id",
          "country"
        ],
        "type": "object",
        "properties": {
          "app_id": {
            "minLength": 1,
            "type": "string",
            "description": "App Store app id. A leading id prefix or App Store URL is allowed."
          },
          "country": {
            "minLength": 1,
            "type": "string",
            "description": "Two-letter App Store country code."
          },
          "lang": {
            "type": "string",
            "description": "Optional App Store locale/language, for example en, en-US, or ru.",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "AppKeywordRankingCurrentItem": {
        "required": [
          "date",
          "keyword"
        ],
        "type": "object",
        "properties": {
          "keyword": {
            "type": "string",
            "nullable": true
          },
          "date": {
            "type": "string",
            "format": "date"
          },
          "rank": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "AppKeywordRankingHistoryItem": {
        "required": [
          "app_id",
          "date",
          "keyword"
        ],
        "type": "object",
        "properties": {
          "app_id": {
            "type": "string",
            "nullable": true
          },
          "keyword": {
            "type": "string",
            "nullable": true
          },
          "date": {
            "type": "string",
            "format": "date"
          },
          "rank": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "AppKeywordRankingMoverItem": {
        "required": [
          "keyword"
        ],
        "type": "object",
        "properties": {
          "keyword": {
            "type": "string",
            "nullable": true
          },
          "rank_from": {
            "type": "integer",
            "format": "int32"
          },
          "rank_to": {
            "type": "integer",
            "format": "int32"
          },
          "rank_change": {
            "type": "integer",
            "description": "Always rank_from minus rank_to, independent of calculation.",
            "format": "int32"
          },
          "change": {
            "type": "number",
            "description": "Selected calculation, used for direction, min_change and sorting.",
            "format": "double"
          },
          "average_rank": {
            "type": "number",
            "description": "Mean of observed positive daily ranks; present for table_trend only.",
            "format": "double",
            "nullable": true
          },
          "observed_days": {
            "type": "integer",
            "format": "int32"
          }
        },
        "additionalProperties": false
      },
      "AppKeywordRankingsCurrentRequest": {
        "required": [
          "app_id",
          "country",
          "platform"
        ],
        "type": "object",
        "properties": {
          "app_id": {
            "minLength": 1,
            "type": "string",
            "description": "App Store app id. Required. Values may include or omit the leading id prefix."
          },
          "keywords": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Keyword terms. Optional, maximum 100 normalized keywords. When omitted, returns stored keyword-date rows for yesterday and today using cursor pagination.",
            "nullable": true
          },
          "limit": {
            "maximum": 2147483647,
            "minimum": 0,
            "type": "integer",
            "description": "Maximum number of keyword-date rows returned when keywords is omitted. Default is 10. Use 0 to return all stored yesterday/today keyword-date rows.",
            "format": "int32",
            "default": 10,
            "nullable": true
          },
          "offset": {
            "maximum": 2147483647,
            "minimum": 0,
            "type": "integer",
            "description": "Number of keyword-date rows to skip when keywords is omitted. Requires cursor_id when greater than 0.",
            "format": "int32",
            "default": 0,
            "nullable": true
          },
          "cursor_id": {
            "type": "string",
            "description": "Cursor id from meta.pagination.cursor_id. Required when offset is greater than 0.",
            "nullable": true
          },
          "country": {
            "minLength": 1,
            "type": "string",
            "description": "Two-letter App Store country code. Required."
          },
          "platform": {
            "$ref": "#/components/schemas/KeywordPlatform"
          }
        },
        "additionalProperties": false
      },
      "AppKeywordRankingsCurrentResponse": {
        "required": [
          "meta"
        ],
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AppKeywordRankingCurrentItem"
            },
            "nullable": true
          },
          "meta": {
            "$ref": "#/components/schemas/ResponseMeta"
          }
        },
        "additionalProperties": false
      },
      "AppKeywordRankingsHistoryRequest": {
        "required": [
          "app_ids",
          "country",
          "date_from",
          "date_to",
          "keywords",
          "platform"
        ],
        "type": "object",
        "properties": {
          "app_ids": {
            "minItems": 1,
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "App Store app ids. Required, maximum 5 normalized app ids."
          },
          "keywords": {
            "minItems": 1,
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Keyword terms. Required, maximum 100 normalized keywords."
          },
          "country": {
            "minLength": 1,
            "type": "string",
            "description": "Two-letter App Store country code. Required."
          },
          "platform": {
            "$ref": "#/components/schemas/KeywordPlatform"
          },
          "date_from": {
            "type": "string",
            "description": "Start date, inclusive. Required.",
            "format": "date"
          },
          "date_to": {
            "type": "string",
            "description": "End date, inclusive. Required. Must be greater than or equal to date_from; maximum range is 60 days.",
            "format": "date"
          }
        },
        "additionalProperties": false
      },
      "AppKeywordRankingsHistoryResponse": {
        "required": [
          "meta"
        ],
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AppKeywordRankingHistoryItem"
            },
            "nullable": true
          },
          "meta": {
            "$ref": "#/components/schemas/ResponseMeta"
          }
        },
        "additionalProperties": false
      },
      "AppKeywordRankingsMoversCalculation": {
        "enum": [
          "delta",
          "table_trend"
        ],
        "type": "string"
      },
      "AppKeywordRankingsMoversComparison": {
        "required": [
          "app_id",
          "country",
          "platform"
        ],
        "type": "object",
        "properties": {
          "app_id": {
            "type": "string",
            "nullable": true
          },
          "country": {
            "type": "string",
            "nullable": true
          },
          "platform": {
            "type": "string",
            "nullable": true
          },
          "direction": {
            "$ref": "#/components/schemas/AppKeywordRankingsMoversDirection"
          },
          "calculation": {
            "$ref": "#/components/schemas/AppKeywordRankingsMoversCalculation"
          },
          "period_days": {
            "type": "integer",
            "format": "int32"
          },
          "date_from": {
            "type": "string",
            "format": "date"
          },
          "date_to": {
            "type": "string",
            "format": "date"
          }
        },
        "additionalProperties": false
      },
      "AppKeywordRankingsMoversDirection": {
        "enum": [
          "growing",
          "falling"
        ],
        "type": "string"
      },
      "AppKeywordRankingsMoversRequest": {
        "required": [
          "app_id",
          "country",
          "direction",
          "platform"
        ],
        "type": "object",
        "properties": {
          "app_id": {
            "minLength": 1,
            "type": "string",
            "description": "App Store app id. Required; a leading id prefix is allowed."
          },
          "country": {
            "minLength": 1,
            "type": "string",
            "description": "Supported two-letter keyword country code. Required."
          },
          "platform": {
            "$ref": "#/components/schemas/KeywordPlatform"
          },
          "direction": {
            "$ref": "#/components/schemas/AppKeywordRankingsMoversDirection"
          },
          "calculation": {
            "allOf": [
              {
                "$ref": "#/components/schemas/AppKeywordRankingsMoversCalculation"
              }
            ],
            "description": "delta: first rank minus last rank. table_trend: average observed daily rank minus last rank, without rounding or missing-rank substitutes.",
            "default": "delta"
          },
          "period_days": {
            "enum": [
              1,
              7,
              14,
              30
            ],
            "type": "integer",
            "description": "Distance between boundary dates: 1, 7, 14, or 30 days. Ends yesterday UTC. A 30-day period includes 31 calendar dates.",
            "format": "int32",
            "default": 7
          },
          "keywords": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Optional restriction to at most 100 normalized keywords. Omit to consider all stored app keywords in the period.",
            "nullable": true
          },
          "limit": {
            "maximum": 200,
            "minimum": 1,
            "type": "integer",
            "description": "Maximum returned movers, 1..200. Applied after filtering and sorting.",
            "format": "int32",
            "default": 50
          },
          "min_change": {
            "maximum": 2147483647,
            "minimum": 5E-324,
            "type": "number",
            "description": "Minimum absolute change in the selected calculation. Positive; default 1.",
            "format": "double",
            "default": 1
          },
          "max_rank": {
            "maximum": 2147483647,
            "minimum": 1,
            "type": "integer",
            "description": "Optional maximum position at the final date, inclusive.",
            "format": "int32",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "AppKeywordRankingsMoversResponse": {
        "required": [
          "comparison",
          "meta",
          "summary"
        ],
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AppKeywordRankingMoverItem"
            },
            "nullable": true
          },
          "comparison": {
            "$ref": "#/components/schemas/AppKeywordRankingsMoversComparison"
          },
          "summary": {
            "$ref": "#/components/schemas/AppKeywordRankingsMoversSummary"
          },
          "meta": {
            "$ref": "#/components/schemas/ResponseMeta"
          }
        },
        "additionalProperties": false
      },
      "AppKeywordRankingsMoversSummary": {
        "type": "object",
        "properties": {
          "considered_keywords": {
            "type": "integer",
            "description": "Explicit normalized keyword count, or distinct stored app keywords within the period.",
            "format": "int64"
          },
          "comparable_keywords": {
            "type": "integer",
            "format": "int64"
          },
          "excluded_keywords": {
            "type": "integer",
            "format": "int64"
          },
          "matched_keywords": {
            "type": "integer",
            "description": "Comparable keywords matching all filters before limit.",
            "format": "int64"
          }
        },
        "additionalProperties": false
      },
      "AppKeywordRankingsQueryRequest": {
        "required": [
          "app_id",
          "country",
          "keywords",
          "platform"
        ],
        "type": "object",
        "properties": {
          "app_id": {
            "minLength": 1,
            "type": "string",
            "description": "App Store app id. Required. Values may include or omit the leading id prefix."
          },
          "keywords": {
            "minItems": 1,
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Keyword terms. Required, maximum 100 normalized keywords."
          },
          "country": {
            "minLength": 1,
            "type": "string",
            "description": "Two-letter App Store country code. Required."
          },
          "platform": {
            "$ref": "#/components/schemas/KeywordPlatform"
          },
          "date_from": {
            "type": "string",
            "description": "Start date, inclusive. Optional. Omit both date_from and date_to to return yesterday and today UTC.",
            "format": "date",
            "nullable": true
          },
          "date_to": {
            "type": "string",
            "description": "End date, inclusive. Optional. Must be provided with date_from and be greater than or equal to date_from.",
            "format": "date",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "AppKeywordRankingsQueryResponse": {
        "required": [
          "meta"
        ],
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AppKeywordRankingHistoryItem"
            },
            "nullable": true
          },
          "meta": {
            "$ref": "#/components/schemas/ResponseMeta"
          }
        },
        "additionalProperties": false
      },
      "AppRankingItem": {
        "required": [
          "app_id",
          "country",
          "date",
          "platform",
          "rank",
          "type"
        ],
        "type": "object",
        "properties": {
          "app_id": {
            "type": "string",
            "nullable": true
          },
          "country": {
            "type": "string",
            "nullable": true
          },
          "date": {
            "type": "string",
            "format": "date"
          },
          "platform": {
            "$ref": "#/components/schemas/AppRankingPlatform"
          },
          "type": {
            "$ref": "#/components/schemas/AppRankingType"
          },
          "category_id": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "category": {
            "type": "string",
            "nullable": true
          },
          "rank": {
            "type": "integer",
            "format": "int32"
          }
        },
        "additionalProperties": false
      },
      "AppRankingPlatform": {
        "enum": [
          "ios",
          "ipad",
          "mac"
        ],
        "type": "string"
      },
      "AppRankingType": {
        "enum": [
          "free",
          "paid",
          "grossing"
        ],
        "type": "string"
      },
      "AppRankingsCurrentRequest": {
        "required": [
          "app_id",
          "platform"
        ],
        "type": "object",
        "properties": {
          "app_id": {
            "minLength": 1,
            "type": "string",
            "description": "App Store app id. A leading id prefix or App Store URL is allowed."
          },
          "platform": {
            "$ref": "#/components/schemas/AppRankingPlatform"
          },
          "countries": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Optional App Store country codes. When omitted, rankings from all stored countries may be returned.",
            "nullable": true
          },
          "types": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AppRankingType"
            },
            "description": "Optional ranking types. Supported values are free, paid, and grossing.",
            "nullable": true
          },
          "category_ids": {
            "type": "array",
            "items": {
              "type": "integer",
              "format": "int32"
            },
            "description": "Optional App Store category ids, for example 6014 for Games or 7012 for Puzzle.",
            "nullable": true
          },
          "limit": {
            "maximum": 1000,
            "minimum": 1,
            "type": "integer",
            "description": "Maximum number of ranking rows returned. Default is 100, maximum is 1000.",
            "format": "int32",
            "default": 100,
            "nullable": true
          },
          "offset": {
            "maximum": 2147483647,
            "minimum": 0,
            "type": "integer",
            "description": "Number of ranking rows to skip.",
            "format": "int32",
            "default": 0,
            "nullable": true
          },
          "date": {
            "type": "string",
            "description": "Ranking snapshot date. When omitted, the latest available daily snapshot is returned. Earliest supported date is 2024-09-15.",
            "format": "date",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "AppRankingsHistoryRequest": {
        "required": [
          "app_id",
          "date_from",
          "date_to",
          "platform"
        ],
        "type": "object",
        "properties": {
          "app_id": {
            "minLength": 1,
            "type": "string",
            "description": "App Store app id. A leading id prefix or App Store URL is allowed."
          },
          "platform": {
            "$ref": "#/components/schemas/AppRankingPlatform"
          },
          "countries": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Optional App Store country codes. When omitted, rankings from all stored countries may be returned.",
            "nullable": true
          },
          "types": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AppRankingType"
            },
            "description": "Optional ranking types. Supported values are free, paid, and grossing.",
            "nullable": true
          },
          "category_ids": {
            "type": "array",
            "items": {
              "type": "integer",
              "format": "int32"
            },
            "description": "Optional App Store category ids, for example 6014 for Games or 7012 for Puzzle.",
            "nullable": true
          },
          "limit": {
            "maximum": 1000,
            "minimum": 1,
            "type": "integer",
            "description": "Maximum number of ranking rows returned. Default is 100, maximum is 1000.",
            "format": "int32",
            "default": 100,
            "nullable": true
          },
          "offset": {
            "maximum": 2147483647,
            "minimum": 0,
            "type": "integer",
            "description": "Number of ranking rows to skip.",
            "format": "int32",
            "default": 0,
            "nullable": true
          },
          "date_from": {
            "type": "string",
            "description": "Start ranking date, inclusive. Required. Earliest supported date is 2024-09-15.",
            "format": "date"
          },
          "date_to": {
            "type": "string",
            "description": "End ranking date, inclusive. Required. Maximum range is 180 days.",
            "format": "date"
          }
        },
        "additionalProperties": false
      },
      "AppRankingsResponse": {
        "required": [
          "meta"
        ],
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AppRankingItem"
            },
            "nullable": true
          },
          "meta": {
            "$ref": "#/components/schemas/ResponseMeta"
          }
        },
        "additionalProperties": false
      },
      "AppReviewDeveloperResponse": {
        "type": "object",
        "properties": {
          "body": {
            "type": "string",
            "nullable": true
          },
          "modified_at_utc": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "AppReviewItem": {
        "required": [
          "app_id",
          "country",
          "date_utc",
          "rating",
          "review_id"
        ],
        "type": "object",
        "properties": {
          "review_id": {
            "type": "string",
            "nullable": true
          },
          "app_id": {
            "type": "string",
            "nullable": true
          },
          "country": {
            "type": "string",
            "nullable": true
          },
          "date_utc": {
            "type": "string",
            "format": "date-time"
          },
          "rating": {
            "type": "integer",
            "format": "int32"
          },
          "title": {
            "type": "string",
            "nullable": true
          },
          "content": {
            "type": "string",
            "nullable": true
          },
          "author_name": {
            "type": "string",
            "nullable": true
          },
          "version": {
            "type": "string",
            "nullable": true
          },
          "vote_count": {
            "type": "integer",
            "format": "int32"
          },
          "developer_response": {
            "$ref": "#/components/schemas/AppReviewDeveloperResponse"
          }
        },
        "additionalProperties": false
      },
      "AppReviewsQueryRequest": {
        "required": [
          "app_id"
        ],
        "type": "object",
        "properties": {
          "app_id": {
            "minLength": 1,
            "type": "string",
            "description": "App Store app id. A leading id prefix or App Store URL is allowed."
          },
          "countries": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Optional App Store country codes. When omitted, reviews from all stored countries may be returned.",
            "nullable": true
          },
          "ratings": {
            "type": "array",
            "items": {
              "type": "integer",
              "format": "int32"
            },
            "description": "Optional star ratings to include. Allowed values are 1 through 5.",
            "nullable": true
          },
          "versions": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Optional app versions to include.",
            "nullable": true
          },
          "keyword": {
            "type": "string",
            "description": "Optional full-text filter applied to review title and body.",
            "nullable": true
          },
          "has_reply": {
            "type": "boolean",
            "description": "Optional developer reply filter.",
            "nullable": true
          },
          "date_from": {
            "type": "string",
            "description": "Start review date, inclusive.",
            "format": "date",
            "nullable": true
          },
          "date_to": {
            "type": "string",
            "description": "End review date, inclusive.",
            "format": "date",
            "nullable": true
          },
          "limit": {
            "maximum": 10000,
            "minimum": 1,
            "type": "integer",
            "description": "Maximum number of reviews returned. Default is 100, maximum is 10000.",
            "format": "int32",
            "default": 100,
            "nullable": true
          },
          "offset": {
            "maximum": 2147483647,
            "minimum": 0,
            "type": "integer",
            "description": "Number of reviews to skip.",
            "format": "int32",
            "default": 0,
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "AppReviewsQueryResponse": {
        "required": [
          "meta"
        ],
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AppReviewItem"
            },
            "nullable": true
          },
          "meta": {
            "$ref": "#/components/schemas/ResponseMeta"
          }
        },
        "additionalProperties": false
      },
      "AppSummary": {
        "type": "object",
        "properties": {
          "app_id": {
            "type": "string",
            "nullable": true
          },
          "url": {
            "type": "string",
            "description": "Public App Store product page URL.",
            "nullable": true
          },
          "icon_url": {
            "type": "string",
            "nullable": true
          },
          "rating": {
            "type": "number",
            "description": "Average App Store user rating.",
            "format": "double",
            "nullable": true
          },
          "primary_genre": {
            "$ref": "#/components/schemas/AppSummaryGenre"
          },
          "secondary_genres": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AppSummaryGenre"
            },
            "nullable": true
          },
          "title": {
            "type": "string",
            "nullable": true
          },
          "subtitle": {
            "type": "string",
            "nullable": true
          },
          "description": {
            "type": "string",
            "nullable": true
          },
          "bundle_id": {
            "type": "string",
            "nullable": true
          },
          "rating_count": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "rating_count_list": {
            "type": "array",
            "items": {
              "type": "integer",
              "format": "int32"
            },
            "nullable": true
          },
          "release_date": {
            "type": "string",
            "format": "date",
            "nullable": true
          },
          "developer_name": {
            "type": "string",
            "nullable": true
          },
          "version": {
            "type": "string",
            "nullable": true
          },
          "price": {
            "type": "string",
            "nullable": true
          },
          "has_in_app_purchases": {
            "type": "boolean",
            "nullable": true
          },
          "in_app_purchases": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AppChartInAppPurchase"
            },
            "nullable": true
          },
          "age_rating": {
            "type": "string",
            "nullable": true
          },
          "website": {
            "type": "string",
            "nullable": true
          },
          "support_url": {
            "type": "string",
            "nullable": true
          },
          "privacy_policy_url": {
            "type": "string",
            "nullable": true
          },
          "copyright": {
            "type": "string",
            "nullable": true
          },
          "date_check_utc": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Flat app metadata shared by the app summary and chart enrichment responses."
      },
      "AppSummaryGenre": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "nullable": true
          },
          "name": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Stable genre ID and its localized display name; provider order determines primary/secondary."
      },
      "AppSummaryQueryRequest": {
        "required": [
          "app_id",
          "country"
        ],
        "type": "object",
        "properties": {
          "app_id": {
            "minLength": 1,
            "type": "string",
            "description": "App Store app id. A leading id prefix or App Store URL is allowed."
          },
          "country": {
            "minLength": 1,
            "type": "string",
            "description": "Two-letter App Store country code."
          },
          "lang": {
            "type": "string",
            "description": "Optional App Store locale/language, for example en, en-US, or ru.",
            "nullable": true
          },
          "platform": {
            "$ref": "#/components/schemas/AppRankingPlatform"
          }
        },
        "additionalProperties": false
      },
      "AppSummaryResponse": {
        "required": [
          "data",
          "meta"
        ],
        "type": "object",
        "properties": {
          "data": {
            "$ref": "#/components/schemas/AppSummary"
          },
          "meta": {
            "$ref": "#/components/schemas/ResponseMeta"
          }
        },
        "additionalProperties": false
      },
      "AuthClientResponse": {
        "required": [
          "id",
          "name",
          "role"
        ],
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Public API key identifier.",
            "nullable": true
          },
          "name": {
            "type": "string",
            "description": "Public API client display name.",
            "nullable": true
          },
          "role": {
            "type": "string",
            "description": "Public API client role.",
            "nullable": true
          },
          "email": {
            "type": "string",
            "description": "Email attached to the authenticated API key.",
            "nullable": true
          },
          "partner_id": {
            "type": "string",
            "description": "Partner identifier when the key belongs to a partner.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Authenticated public API client information."
      },
      "AuthTestResponse": {
        "required": [
          "client",
          "meta",
          "surface"
        ],
        "type": "object",
        "properties": {
          "status": {
            "type": "string",
            "description": "Current endpoint status.",
            "nullable": true
          },
          "surface": {
            "type": "string",
            "description": "Active public API surface.",
            "nullable": true
          },
          "api_version": {
            "type": "string",
            "description": "Public API version served by this endpoint.",
            "nullable": true
          },
          "client": {
            "$ref": "#/components/schemas/AuthClientResponse"
          },
          "meta": {
            "$ref": "#/components/schemas/ResponseMeta"
          }
        },
        "additionalProperties": false,
        "description": "Response returned by the public API smoke/auth test endpoint."
      },
      "CollectedKeywordSearchResultsAppItem": {
        "required": [
          "app_id"
        ],
        "type": "object",
        "properties": {
          "app_id": {
            "type": "string",
            "nullable": true
          },
          "rank": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "CollectedKeywordSearchResultsItem": {
        "required": [
          "country",
          "platform",
          "term"
        ],
        "type": "object",
        "properties": {
          "term": {
            "type": "string",
            "nullable": true
          },
          "country": {
            "type": "string",
            "nullable": true
          },
          "platform": {
            "$ref": "#/components/schemas/KeywordPlatform"
          },
          "last_updated": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "apps": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CollectedKeywordSearchResultsAppItem"
            },
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "CollectedKeywordSearchResultsRequest": {
        "required": [
          "country",
          "keywords",
          "platform"
        ],
        "type": "object",
        "properties": {
          "app_id": {
            "type": "string",
            "description": "App scope field. It does not affect collected search results; the response contains top organic apps only.",
            "nullable": true
          },
          "country": {
            "maxLength": 2,
            "minLength": 2,
            "type": "string",
            "description": "Two-letter App Store country code. Required."
          },
          "platform": {
            "$ref": "#/components/schemas/KeywordPlatform"
          },
          "keywords": {
            "minItems": 1,
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Keyword terms. Required, at least one normalized keyword."
          },
          "limit": {
            "maximum": 10,
            "minimum": 1,
            "type": "integer",
            "description": "Maximum number of app rows returned per keyword. Defaults to 10, maximum 10.",
            "format": "int32",
            "default": 10,
            "nullable": true
          },
          "offset": {
            "maximum": 2147483647,
            "minimum": 0,
            "type": "integer",
            "description": "Number of app rows to skip per keyword. Requires request_id when greater than 0.",
            "format": "int32",
            "default": 0,
            "nullable": true
          },
          "request_id": {
            "type": "string",
            "description": "Original first-page request id. Required when offset is greater than 0.",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "CollectedKeywordSearchResultsResponse": {
        "required": [
          "meta"
        ],
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CollectedKeywordSearchResultsItem"
            },
            "nullable": true
          },
          "meta": {
            "$ref": "#/components/schemas/ResponseMeta"
          }
        },
        "additionalProperties": false
      },
      "DeleteKeywordListEntryResponse": {
        "required": [
          "data",
          "meta"
        ],
        "type": "object",
        "properties": {
          "data": {
            "$ref": "#/components/schemas/DeleteKeywordListEntryResult"
          },
          "meta": {
            "$ref": "#/components/schemas/ResponseMeta"
          }
        },
        "additionalProperties": false
      },
      "DeleteKeywordListEntryResult": {
        "required": [
          "tracking_id"
        ],
        "type": "object",
        "properties": {
          "tracking_id": {
            "type": "string",
            "nullable": true
          },
          "deleted": {
            "type": "boolean"
          }
        },
        "additionalProperties": false
      },
      "KeywordListEntry": {
        "required": [
          "app_id",
          "country",
          "keyword",
          "platform",
          "project_id",
          "tracking_id"
        ],
        "type": "object",
        "properties": {
          "tracking_id": {
            "type": "string",
            "nullable": true
          },
          "project_id": {
            "type": "string",
            "nullable": true
          },
          "app_id": {
            "type": "string",
            "nullable": true
          },
          "keyword": {
            "type": "string",
            "nullable": true
          },
          "country": {
            "type": "string",
            "nullable": true
          },
          "platform": {
            "$ref": "#/components/schemas/KeywordPlatform"
          },
          "updated_at_utc": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "KeywordListMutationResponse": {
        "required": [
          "data",
          "meta"
        ],
        "type": "object",
        "properties": {
          "data": {
            "$ref": "#/components/schemas/KeywordListMutationResult"
          },
          "meta": {
            "$ref": "#/components/schemas/ResponseMeta"
          }
        },
        "additionalProperties": false
      },
      "KeywordListMutationResult": {
        "required": [
          "app_id",
          "country",
          "platform",
          "project_id"
        ],
        "type": "object",
        "properties": {
          "project_id": {
            "type": "string",
            "nullable": true
          },
          "app_id": {
            "type": "string",
            "nullable": true
          },
          "country": {
            "type": "string",
            "nullable": true
          },
          "platform": {
            "$ref": "#/components/schemas/KeywordPlatform"
          },
          "added": {
            "type": "integer",
            "format": "int32"
          },
          "removed": {
            "type": "integer",
            "format": "int32"
          },
          "total": {
            "type": "integer",
            "format": "int32"
          }
        },
        "additionalProperties": false
      },
      "KeywordListsRequest": {
        "required": [
          "app_id",
          "country",
          "platform",
          "project_id"
        ],
        "type": "object",
        "properties": {
          "project_id": {
            "minLength": 1,
            "type": "string",
            "description": "ASO.dev project id. Required."
          },
          "app_id": {
            "minLength": 1,
            "type": "string",
            "description": "App Store app id. Required. Values may include or omit the leading id prefix."
          },
          "country": {
            "minLength": 1,
            "type": "string",
            "description": "Two-letter App Store country code. Required."
          },
          "platform": {
            "$ref": "#/components/schemas/KeywordPlatform"
          },
          "page": {
            "maximum": 2147483647,
            "minimum": 1,
            "type": "integer",
            "description": "One-based page number. Optional, defaults to 1.",
            "format": "int32",
            "default": 1,
            "nullable": true
          },
          "page_size": {
            "maximum": 200,
            "minimum": 1,
            "type": "integer",
            "description": "Page size. Optional, defaults to 50, maximum 200.",
            "format": "int32",
            "default": 50,
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "KeywordListsResponse": {
        "required": [
          "meta"
        ],
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/KeywordListEntry"
            },
            "nullable": true
          },
          "meta": {
            "$ref": "#/components/schemas/ResponseMeta"
          }
        },
        "additionalProperties": false
      },
      "KeywordPlatform": {
        "enum": [
          "ios"
        ],
        "type": "string"
      },
      "KeywordPopularityMetricsItem": {
        "required": [
          "country",
          "platform",
          "term"
        ],
        "type": "object",
        "properties": {
          "term": {
            "type": "string",
            "nullable": true
          },
          "country": {
            "type": "string",
            "nullable": true
          },
          "platform": {
            "$ref": "#/components/schemas/KeywordPlatform"
          },
          "found": {
            "type": "boolean"
          },
          "popularity": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "popularity_date": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "average_from_date": {
            "type": "string",
            "description": "First stored observation date included in the average calculation,\nor the date of the fallback value. Present for the average endpoint.",
            "format": "date",
            "nullable": true
          },
          "average_checks_count": {
            "type": "integer",
            "description": "Number of stored observations used to calculate the average.\nPresent for the average endpoint.",
            "format": "int32",
            "nullable": true
          },
          "last_checked_date": {
            "type": "string",
            "description": "Most recent UTC date with a stored popularity check.\nPresent for the average endpoint.",
            "format": "date",
            "nullable": true
          },
          "checks_last_30_days": {
            "type": "integer",
            "description": "Number of distinct stored check dates in the last 30 UTC calendar days,\nincluding the current date. Present for the average endpoint.",
            "format": "int32",
            "nullable": true
          },
          "checks_last_365_days": {
            "type": "integer",
            "description": "Number of distinct stored check dates in the last 365 UTC calendar days,\nincluding the current date. Present for the average endpoint.",
            "format": "int32",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "KeywordPopularityMetricsResponse": {
        "required": [
          "data",
          "meta"
        ],
        "type": "object",
        "properties": {
          "data": {
            "$ref": "#/components/schemas/KeywordPopularityMetricsItem"
          },
          "meta": {
            "$ref": "#/components/schemas/ResponseMeta"
          }
        },
        "additionalProperties": false
      },
      "KeywordSearchResultApp": {
        "required": [
          "app_id"
        ],
        "type": "object",
        "properties": {
          "app_id": {
            "type": "string",
            "nullable": true
          },
          "rank": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "KeywordSearchResultsItem": {
        "required": [
          "country",
          "keyword",
          "platform"
        ],
        "type": "object",
        "properties": {
          "keyword": {
            "type": "string",
            "nullable": true
          },
          "country": {
            "type": "string",
            "nullable": true
          },
          "platform": {
            "$ref": "#/components/schemas/KeywordPlatform"
          },
          "rank": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "results": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/KeywordSearchResultApp"
            },
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "KeywordSearchResultsResponse": {
        "required": [
          "data",
          "meta"
        ],
        "type": "object",
        "properties": {
          "data": {
            "$ref": "#/components/schemas/KeywordSearchResultsItem"
          },
          "meta": {
            "$ref": "#/components/schemas/ResponseMeta"
          }
        },
        "additionalProperties": false
      },
      "LatestKeywordSearchResultsRequest": {
        "required": [
          "country",
          "keyword",
          "platform"
        ],
        "type": "object",
        "properties": {
          "app_id": {
            "type": "string",
            "description": "App Store app id. Optional. When omitted, the response returns the latest stored organic result page.",
            "nullable": true
          },
          "keyword": {
            "minLength": 1,
            "type": "string",
            "description": "Keyword term. Required."
          },
          "country": {
            "minLength": 1,
            "type": "string",
            "description": "Two-letter App Store country code. Required."
          },
          "platform": {
            "$ref": "#/components/schemas/KeywordPlatform"
          }
        },
        "additionalProperties": false
      },
      "LiveKeywordSearchResultsRequest": {
        "required": [
          "country",
          "keyword",
          "platform"
        ],
        "type": "object",
        "properties": {
          "app_id": {
            "type": "string",
            "description": "App Store app id. Optional. When omitted, the response returns the full live organic result page.",
            "nullable": true
          },
          "keyword": {
            "minLength": 1,
            "type": "string",
            "description": "Keyword term. Required."
          },
          "country": {
            "minLength": 1,
            "type": "string",
            "description": "Two-letter App Store country code. Required."
          },
          "platform": {
            "$ref": "#/components/schemas/KeywordPlatform"
          }
        },
        "additionalProperties": false
      },
      "ProblemDetails": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "nullable": true
          },
          "title": {
            "type": "string",
            "nullable": true
          },
          "status": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "detail": {
            "type": "string",
            "nullable": true
          },
          "instance": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": { }
      },
      "ProjectListItemResponse": {
        "required": [
          "name",
          "project_id"
        ],
        "type": "object",
        "properties": {
          "project_id": {
            "type": "string",
            "nullable": true
          },
          "name": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "ProjectsListResponse": {
        "required": [
          "meta"
        ],
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ProjectListItemResponse"
            },
            "nullable": true
          },
          "meta": {
            "$ref": "#/components/schemas/ResponseMeta"
          }
        },
        "additionalProperties": false
      },
      "PublicApiRateLimitProblemDetails": {
        "required": [
          "detail",
          "error_code",
          "request_id",
          "status",
          "title",
          "type"
        ],
        "type": "object",
        "properties": {
          "type": {
            "minLength": 1,
            "type": "string",
            "description": "Stable URI identifying the error type."
          },
          "title": {
            "minLength": 1,
            "type": "string",
            "description": "Short human-readable error title."
          },
          "status": {
            "type": "integer",
            "description": "HTTP status code. Always 429 for this contract.",
            "format": "int32"
          },
          "detail": {
            "minLength": 1,
            "type": "string",
            "description": "Human-readable explanation including the exhausted limit or no-data block."
          },
          "error_code": {
            "minLength": 1,
            "type": "string",
            "description": "Stable machine-readable error code."
          },
          "request_id": {
            "minLength": 1,
            "type": "string",
            "description": "Public request identifier for tracing and support."
          },
          "quota_scope": {
            "type": "string",
            "description": "Exhausted quota scope, such as api, dry_run, no_data, or operation:<operation_id>.",
            "nullable": true
          },
          "quota_limit_type": {
            "type": "string",
            "description": "Exhausted limit type: window, minute, hour, day, month, or ratio.",
            "nullable": true
          },
          "quota_limit": {
            "type": "integer",
            "description": "Numeric limit for the exhausted quota.",
            "format": "int64",
            "nullable": true
          },
          "quota_window_seconds": {
            "type": "integer",
            "description": "Fixed quota or observation window length in seconds.",
            "format": "int32",
            "nullable": true
          },
          "block_reason": {
            "type": "string",
            "description": "Machine-readable reason for a temporary key block.",
            "nullable": true
          },
          "blocked_until_utc": {
            "type": "string",
            "description": "UTC timestamp after which a temporarily blocked key can retry.",
            "format": "date-time",
            "nullable": true
          },
          "evaluated_requests": {
            "type": "integer",
            "description": "Number of successful data requests used to evaluate the no-data ratio.",
            "format": "int64",
            "nullable": true
          },
          "no_data_requests": {
            "type": "integer",
            "description": "Number of no-data responses in the evaluated window.",
            "format": "int64",
            "nullable": true
          },
          "no_data_rate_percent": {
            "type": "number",
            "description": "No-data response rate in percent for the evaluated window.",
            "format": "double",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "ProblemDetails returned when a Public API request is rejected with HTTP 429."
      },
      "ReplaceKeywordListRequest": {
        "required": [
          "app_id",
          "country",
          "keywords",
          "platform",
          "project_id"
        ],
        "type": "object",
        "properties": {
          "project_id": {
            "minLength": 1,
            "type": "string",
            "description": "ASO.dev project id. Required."
          },
          "app_id": {
            "minLength": 1,
            "type": "string",
            "description": "App Store app id. Required. Values may include or omit the leading id prefix."
          },
          "country": {
            "minLength": 1,
            "type": "string",
            "description": "Two-letter App Store country code. Required."
          },
          "platform": {
            "$ref": "#/components/schemas/KeywordPlatform"
          },
          "keywords": {
            "minItems": 1,
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Replacement tracked keyword terms. Required, 1 to 200 normalized keywords."
          }
        },
        "additionalProperties": false
      },
      "ResponseMeta": {
        "required": [
          "request_id"
        ],
        "type": "object",
        "properties": {
          "request_id": {
            "type": "string",
            "description": "Server-side request identifier. Mirrors X-Request-ID when the client provides it.",
            "nullable": true
          },
          "usage": {
            "$ref": "#/components/schemas/ResponseUsage"
          },
          "pagination": {
            "$ref": "#/components/schemas/ResponsePagination"
          },
          "timestamp_utc": {
            "type": "string",
            "description": "UTC timestamp when the response was produced.",
            "format": "date-time"
          }
        },
        "additionalProperties": false,
        "description": "Common metadata returned by public API responses."
      },
      "ResponsePagination": {
        "type": "object",
        "properties": {
          "cursor_id": {
            "type": "string",
            "description": "Cursor id for fetching later pages from the same saved result set.",
            "nullable": true
          },
          "limit": {
            "type": "integer",
            "description": "Maximum rows returned per page.",
            "format": "int32"
          },
          "offset": {
            "type": "integer",
            "description": "Rows skipped before this page.",
            "format": "int32"
          },
          "total": {
            "type": "integer",
            "description": "Total rows available for the paginated list.",
            "format": "int32"
          },
          "has_more": {
            "type": "boolean",
            "description": "True when another page is available."
          }
        },
        "additionalProperties": false
      },
      "ResponseUsage": {
        "required": [
          "pricing_policy_version",
          "status"
        ],
        "type": "object",
        "properties": {
          "pricing_policy_version": {
            "type": "string",
            "description": "Pricing policy version used to estimate this request.",
            "nullable": true
          },
          "billing_unit": {
            "type": "string",
            "description": "Unit being priced, such as request, keyword, or keyword_country_platform.",
            "nullable": true
          },
          "units": {
            "type": "integer",
            "description": "Count of priced units.",
            "format": "int64"
          },
          "credits_spent": {
            "type": "integer",
            "description": "Operation cost before balance charging rules are applied.",
            "format": "int64"
          },
          "credits_charged": {
            "type": "integer",
            "description": "Credits actually debited from the account balance. Partner calls may be tracked with zero charged credits.",
            "format": "int64"
          },
          "balance_after": {
            "type": "integer",
            "description": "Developer account balance after the charge, when a balance debit happened.",
            "format": "int64",
            "nullable": true
          },
          "status": {
            "type": "string",
            "description": "Billing status, such as charged, tracked, dry_run, no_data, not_billable, or duplicate.",
            "nullable": true
          },
          "original_request_id": {
            "type": "string",
            "description": "Original first-page request id for snapshot pages.",
            "nullable": true
          },
          "original_units": {
            "type": "integer",
            "description": "Original first-page priced unit count for snapshot pages.",
            "format": "int64",
            "nullable": true
          },
          "original_credits_spent": {
            "type": "integer",
            "description": "Original first-page operation cost for snapshot pages.",
            "format": "int64",
            "nullable": true
          },
          "original_credits_charged": {
            "type": "integer",
            "description": "Original first-page charged credits for snapshot pages.",
            "format": "int64",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "SupportedAppCategoriesResponse": {
        "required": [
          "meta"
        ],
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SupportedAppCategoryResponse"
            },
            "nullable": true
          },
          "meta": {
            "$ref": "#/components/schemas/ResponseMeta"
          }
        },
        "additionalProperties": false
      },
      "SupportedAppCategoryResponse": {
        "required": [
          "category_id",
          "is_aggregate",
          "name",
          "slug"
        ],
        "type": "object",
        "properties": {
          "category_id": {
            "type": "integer",
            "format": "int32"
          },
          "name": {
            "type": "string",
            "nullable": true
          },
          "slug": {
            "type": "string",
            "nullable": true
          },
          "parent_category_id": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "is_aggregate": {
            "type": "boolean"
          }
        },
        "additionalProperties": false
      },
      "SupportedCountriesResponse": {
        "required": [
          "meta"
        ],
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SupportedCountryResponse"
            },
            "nullable": true
          },
          "meta": {
            "$ref": "#/components/schemas/ResponseMeta"
          }
        },
        "additionalProperties": false
      },
      "SupportedCountryResponse": {
        "required": [
          "code"
        ],
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "SurfaceTestResponse": {
        "required": [
          "meta",
          "surface"
        ],
        "type": "object",
        "properties": {
          "status": {
            "type": "string",
            "description": "Current endpoint status.",
            "nullable": true
          },
          "surface": {
            "type": "string",
            "description": "Active public API surface.",
            "nullable": true
          },
          "api_version": {
            "type": "string",
            "description": "Public API version served by this endpoint.",
            "nullable": true
          },
          "meta": {
            "$ref": "#/components/schemas/ResponseMeta"
          }
        },
        "additionalProperties": false,
        "description": "Response returned by surface-specific smoke endpoints."
      },
      "UpdateKeywordListRequest": {
        "required": [
          "app_id",
          "country",
          "platform",
          "project_id"
        ],
        "type": "object",
        "properties": {
          "project_id": {
            "minLength": 1,
            "type": "string",
            "description": "ASO.dev project id. Required."
          },
          "app_id": {
            "minLength": 1,
            "type": "string",
            "description": "App Store app id. Required. Values may include or omit the leading id prefix."
          },
          "country": {
            "minLength": 1,
            "type": "string",
            "description": "Two-letter App Store country code. Required."
          },
          "platform": {
            "$ref": "#/components/schemas/KeywordPlatform"
          },
          "add_keywords": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Keyword terms to add. Optional, but at least one add_keywords or remove_keywords value is required.",
            "nullable": true
          },
          "remove_keywords": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Keyword terms to remove. Optional, but at least one add_keywords or remove_keywords value is required.",
            "nullable": true
          }
        },
        "additionalProperties": false
      }
    },
    "securitySchemes": {
      "ApiKeyAuth": {
        "type": "apiKey",
        "description": "Public API key header.",
        "name": "X-API-Key",
        "in": "header"
      }
    }
  },
  "tags": [
    {
      "name": "App Keyword Rankings"
    },
    {
      "name": "AppCharts"
    },
    {
      "name": "AppRankings"
    },
    {
      "name": "AppReviews"
    },
    {
      "name": "Apps"
    },
    {
      "name": "Auth"
    },
    {
      "name": "Developer"
    },
    {
      "name": "Dictionaries"
    },
    {
      "name": "Keyword Lists"
    },
    {
      "name": "Keyword Metrics"
    },
    {
      "name": "Keyword Search Results"
    },
    {
      "name": "Projects"
    }
  ],
  "externalDocs": {
    "description": "ASO.dev Public API portal.",
    "url": "https://developer.aso.dev/dashboard/"
  },
  "x-aso-portal-url": "https://developer.aso.dev/dashboard/"
}