{
    "api_version": "1",
    "documentation": {
        "url": "https://roms.danielspringer.at/api/ota.php?help=1",
        "human_url": "https://roms.danielspringer.at/api/ota.php?help=1&format=html",
        "description": "Public, read-only catalog of OnePlus, OPPO, Realme, Xiaomi, Redmi, and POCO OTA entries.",
        "methods": [
            "GET",
            "HEAD",
            "OPTIONS"
        ],
        "filters": {
            "device": "Filter by the device label, case-insensitive.",
            "region": "Filter by the region code, case-insensitive.",
            "model": "Filter by the canonical model code, case-insensitive.",
            "id": "Return the release with this ID.",
            "latest": "Set to 1 to return only the newest release for each matching device and region.",
            "since": "Return releases with a vendor build timestamp newer than this ISO 8601 date or timestamp."
        },
        "examples": {
            "all_releases": "https://roms.danielspringer.at/api/ota.php",
            "by_device": "https://roms.danielspringer.at/api/ota.php?device=OP+13",
            "by_device_and_region": "https://roms.danielspringer.at/api/ota.php?device=OP+13&region=EU",
            "by_model": "https://roms.danielspringer.at/api/ota.php?model=CPH2653",
            "latest_for_device_region": "https://roms.danielspringer.at/api/ota.php?device=OP+13&region=EU&latest=1",
            "built_since": "https://roms.danielspringer.at/api/ota.php?since=2026-07-01",
            "by_release_id": "https://roms.danielspringer.at/api/ota.php?id=RELEASE_ID"
        },
        "notes": [
            "source_url is the unresolved source stored in the relevant OTA catalog. Depending on the manufacturer, it can be an OPlus downloadCheck URL or an exact Xiaomi catalog selector.",
            "md5, size, published, and version_code are optional and omitted when the catalog has no validated value.",
            "published is the vendor-supplied publication timestamp in Unix milliseconds and may be revised by the vendor later.",
            "The API does not resolve redirects or generate temporary CDN links.",
            "Use + for every space in device names: OPPO FIND X8 PRO becomes OPPO+FIND+X8+PRO.",
            "Query parameter values should be URL-encoded.",
            "Filters can be combined and are applied with AND semantics.",
            "build_timestamp is extracted from ota_version. Its timezone is not declared by the vendor, so it is not a publication timestamp.",
            "since compares the vendor build timestamp, exclusively. A date means midnight UTC for comparison purposes.",
            "is_latest and latest=1 use the vendor build timestamp, with the natural version order as a deterministic fallback.",
            "Without latest=1, releases retain the original natural ascending device, region, and version ordering.",
            "For efficient polling, store the ETag and send it back in If-None-Match. An unchanged catalog returns HTTP 304."
        ]
    },
    "response_fields": {
        "id": "Stable identifier for this catalog entry.",
        "device": "Device label.",
        "region": "OTA region code.",
        "model": "Canonical device model code extracted from the OTA metadata.",
        "version": "Human-readable release version.",
        "ota_version": "OTA package version from the catalog.",
        "build_timestamp": "Vendor build timestamp extracted from ota_version; timezone unspecified.",
        "security_patch": "Android security patch level, when available.",
        "md5": "MD5 checksum of the complete OTA package, when available.",
        "size": "Size of the complete OTA package in bytes, when available.",
        "published": "Vendor-supplied publication timestamp in Unix milliseconds, when available.",
        "version_code": "Numeric vendor version code, when available.",
        "source_url": "Unresolved source URL stored in the catalog.",
        "changelog_url": "Release changelog URL, when available.",
        "is_latest": "Whether this is the newest catalog entry for its device and region."
    },
    "polling": {
        "cache_seconds": 300,
        "conditional_request_header": "If-None-Match",
        "unchanged_status": 304,
        "recommended_interval_seconds": 900
    }
}
