# How biliTickerBuy Fetches Project Payload to Determine hotProject Status

> Discover how biliTickerBuy fetches project payload using BiliBili APIs to determine hotProject status. Learn about fallback mechanisms and normalized data for ticket demand.

- Repository: [Qizhuo Xie/biliTickerBuy](https://github.com/mikumifa/biliTickerBuy)
- Tags: internals
- Published: 2026-06-23

---

**The `fetch_project_payload()` function in [`interface/project.py`](https://github.com/mikumifa/biliTickerBuy/blob/main/interface/project.py) attempts the new BiliBili API first, falls back to the legacy endpoint on any exception, and returns a normalized dictionary containing the `hotProject` boolean flag that indicates high-demand ticket status.**

The mikumifa/biliTickerBuy repository determines whether a ticket sale qualifies as a "hot project" by fetching metadata from BiliBili's commerce APIs. This project payload fetching mechanism supports two API versions to ensure reliability, extracting the `hotProject` field to dynamically adjust purchasing strategies.

## Entry Point: fetch_project_payload()

The primary interface for retrieving project metadata is located in [`interface/project.py`](https://github.com/mikumifa/biliTickerBuy/blob/main/interface/project.py). The `fetch_project_payload()` function serves as a resilient wrapper that implements a failover pattern between API versions.

```python
def fetch_project_payload(request: Any, project_id: int) -> dict[str, Any]:

```

The function executes the following logic:
1. Attempts to retrieve data via `_fetch_project_payload_new()`
2. If any exception is raised, immediately falls back to `_fetch_project_payload_old()`
3. Returns a standardized dictionary containing the `"hotProject"` key

This dual-path approach ensures the ticket buyer can detect hot projects even when one API endpoint is deprecated or unstable.

## New API Implementation

When the primary endpoint is available, `_fetch_project_payload_new()` performs a `POST` request to `https://mall.bilibili.com/mall-search-items/items_detail/info` with the `itemsId` parameter set to the target project ID.

The response validation checks both `response["success"]` and the `errno` field before proceeding. Upon successful retrieval, the raw payload passes through `_normalize_new_project_payload()`, which explicitly casts the hot status using:

```python
"hotProject": bool(new_payload.get("hotProject", False)),

```

This normalization ensures consistent boolean typing regardless of how the API represents the flag.

## Legacy API Fallback

If the new API raises an exception—whether from network failure, schema changes, or endpoint deprecation—the system falls back to `_fetch_project_payload_old()`. This legacy path sends a `GET` request to `https://show.bilibili.com/api/ticket/project/getV2` with the project ID as a query parameter.

The legacy endpoint returns the `data` dictionary directly when `errno == 0`, which already contains the native `hotProject` field without requiring additional normalization.

## Consuming hotProject in the Purchase Workflow

Downstream components consume this payload to optimize buying behavior. In [`task/buy.py`](https://github.com/mikumifa/biliTickerBuy/blob/main/task/buy.py), the code extracts the status into a local variable:

```python
is_hot_project = bool(tickets_info.get("is_hot_project", False))

```

When `payload["hotProject"]` evaluates to `True`, the system triggers `refresh_hot_and_warm()` to upgrade the purchasing strategy. This allows the automation to adjust timing, polling intervals, or retry logic based on project demand intensity. The flag propagates through the application via structures defined in [`task/buy_helpers.py`](https://github.com/mikumifa/biliTickerBuy/blob/main/task/buy_helpers.py) and surfaces in the UI configuration handled by [`tab/settings.py`](https://github.com/mikumifa/biliTickerBuy/blob/main/tab/settings.py).

### Fetching Example

```python
from biliTickerBuy.interface.project import fetch_project_payload
from biliTickerBuy.util.request.BiliRequest import BiliRequest

request = BiliRequest()
project_id = 123456  # example project id

payload = fetch_project_payload(request=request, project_id=project_id)

if payload["hotProject"]:
    print("🔥 This is a hot project!")
else:
    print("Regular project.")

```

### Integration in Buying Scripts

```python
from biliTickerBuy.task.buy import main as buy_main

# buy_main internally calls fetch_project_payload,

# then uses refresh_hot_and_warm() to upgrade the strategy

# when payload["hotProject"] is True.

buy_main(project_input=123456, cookies_path="cookies.json")

```

## Summary

- **Dual API resilience**: [`interface/project.py`](https://github.com/mikumifa/biliTickerBuy/blob/main/interface/project.py) prioritizes the new mall API but automatically falls back to the legacy show API if exceptions occur.
- **Boolean normalization**: The new API path explicitly casts the `hotProject` field via `bool()` in `_normalize_new_project_payload()`, while the legacy API returns the raw field directly.
- **Strategy adjustment**: [`task/buy.py`](https://github.com/mikumifa/biliTickerBuy/blob/main/task/buy.py) reads the flag to trigger `refresh_hot_and_warm()`, dynamically adapting the purchase behavior for high-demand events.
- **Cross-module propagation**: The status flows from the API layer through [`buy_helpers.py`](https://github.com/mikumifa/biliTickerBuy/blob/main/buy_helpers.py) structures and reaches user configuration in [`tab/settings.py`](https://github.com/mikumifa/biliTickerBuy/blob/main/tab/settings.py).

## Frequently Asked Questions

### What happens if both API endpoints fail?

If `_fetch_project_payload_new()` raises an exception and `_fetch_project_payload_old()` also fails, the exception propagates to the caller. The application does not provide a tertiary fallback, as the project metadata is required to determine ticket availability and purchasing parameters.

### Why does the codebase maintain two different API endpoints?

BiliBili has migrated from the `show.bilibili.com` platform to the `mall.bilibili.com` commerce system. Maintaining both endpoints ensures compatibility with older project IDs while supporting new ticket releases that may only exist in the mall system.

### How does the hotProject flag actually affect the buying behavior?

When `payload["hotProject"]` is `True`, the `refresh_hot_and_warm()` function in [`task/buy.py`](https://github.com/mikumifa/biliTickerBuy/blob/main/task/buy.py) adjusts the purchase strategy. This typically involves modifying request intervals, prioritizing specific ticket tiers, or enabling more aggressive polling patterns to compete for limited inventory on high-demand releases.

### Where is the request object initialized for these API calls?

The `BiliRequest` class defined in [`util/request/BiliRequest.py`](https://github.com/mikumifa/biliTickerBuy/blob/main/util/request/BiliRequest.py) provides the authenticated session object passed as the `request` parameter to `fetch_project_payload()`. This class handles cookie management, headers, and base configuration required for BiliBili API authentication.