> ## Documentation Index
> Fetch the complete documentation index at: https://docs.xapichina.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Python integration

> Use requests for authenticated searches, pagination, details, and report findings.

This example uses a regular HTTP client rather than a China SDK. It keeps your API key on the server and uses supported China parameters.

## Setup

```bash theme={"system"}
python -m pip install requests
export XAPICHINA_API_KEY="xcn_YOUR_KEY"
```

## A reusable client

```python theme={"system"}
import os
import random
import time
import requests

BASE_URL = "https://api.xapichina.com"
session = requests.Session()
session.headers.update({"X-API-Key": os.environ["XAPICHINA_API_KEY"]})

def get_json(path, params=None):
    for attempt in range(3):
        response = session.get(
            BASE_URL + path,
            params=params,
            timeout=(5, 45),
        )
        retry_after = response.headers.get("Retry-After")
        transient = response.status_code in (502, 503)
        throttled = response.status_code == 429 and retry_after is not None
        if attempt < 2 and (transient or throttled):
            delay = int(retry_after) if retry_after and retry_after.isdigit() else 2 ** attempt
            time.sleep(max(1, delay) + random.random())
            continue
        response.raise_for_status()
        return response.json()
```

The helper retries temporary source/service failures and throttling with a retry hint. It does not repeatedly retry monthly-quota errors that lack `Retry-After`. Use a shared queue to pace multiple callers across the account.

## Check your key and search

```python theme={"system"}
allowance = get_json("/v1/me")
print(allowance["plan"], allowance["remaining"])

result = get_json("/v1/search", {
    "brand": "BMW",
    "currency": "cny",
    "price_min": 100000,
    "price_max": 200000,
    "page": 1,
    "lang": "en",
})

for car in result["results"]:
    print(car["id"], car["title"], car["price_cny"], car["price_eur"])
```

## Iterate pages

```python theme={"system"}
def search_pages(filters, maximum_pages=3, spacing_seconds=12):
    page = 1
    seen = set()
    for _ in range(maximum_pages):
        result = get_json("/v1/search", {**filters, "page": page})
        for car in result["results"]:
            if car["id"] not in seen:
                seen.add(car["id"])
                yield car
        page = result["next_page"]
        if page is None:
            return
        time.sleep(spacing_seconds)

for car in search_pages({"brand": "BMW", "lang": "en"}):
    print(car["id"], car["title"])
```

The default delay illustrates Free-plan pacing for this worker; requests from other workers still share its allowance. Set a page budget deliberately instead of crawling every match without a limit.

## Details and reports

```python theme={"system"}
car_id = "59967821"  # replace with an ID returned by your search
detail = get_json(f"/v1/cars/{car_id}", {"lang": "en"})
photos = detail["photos"]  # reuse these without another image call

summary = get_json(f"/v1/cars/{car_id}/inspection", {"lang": "en"})
if summary["data_available"]:
    print(summary["report_provider"], summary["parse_status"])
    for conclusion in summary["conclusions"]:
        print(conclusion["topic"], conclusion.get("label"))
else:
    print("Report findings unavailable:", summary["parse_status"])
```

Each successful detail/report call consumes a request. Queue these calls according to your plan, and handle partial coverage explicitly. See [report interpretation](/inspection-and-insurance) before deriving condition labels.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.