# x-api-rs Python > Python binding for X Web private API automation, backed by Rust `x-api-core`. ## Install ```bash pip install x-api-rs ``` Development build: ```bash maturin develop --manifest-path src/py/Cargo.toml --features "dm upload inbox user posts communities settings search xchat" pytest tests/python/ -v ``` ## Import Use the Web namespace: ```python from x_api_rs.web import Client, WebProfile from x_api_rs import XApiError, InvalidCookiesError, InvalidArgumentError, NetworkError, JsonError, RuntimeXApiError, XChatError ``` Do not use removed compatibility entries such as root-level `Client`, root feature modules, `Twitter` facade classes, or legacy `src/python` paths. ## Create Client ```python client = await Client.create( cookies, proxy_url=None, profile=WebProfile.default_latest(), ) ``` `cookies` must include authenticated X Web cookies such as `ct0`, `auth_token`, and `twid`. ## Auth Token To Cookies If you only have an `auth_token` (no full cookies yet), exchange it for complete cookies first: ```python res = await Client.auth_token_to_cookies(auth_token, proxy_url=None) client = await Client.create(res.cookies) ``` `auth_token_to_cookies` is a `Client` staticmethod that loads `x.com/home` with the token to collect server-issued `ct0`/`twid`, and returns `AuthTokenResult` with fields `cookies`, `ct0`, `user_id`, `auth_token`. It raises `InvalidCookiesError` when the token is invalid or expired. ## WebProfile ```python profile = WebProfile.default_latest() profile = WebProfile.from_spec("chrome:windows:x64") profile = WebProfile.chrome("windows", "x64") # 默认 Chrome 149(对齐 wreq-util 最新桌面模板) profile = WebProfile.chrome("windows", "x64", version=140) # 指定版本(须在当前 wreq-util Emulation 与产品表内;120–149 排除 121/122/125) profile = WebProfile.safari_mac("18.1.1") profile = WebProfile.safari_ios("18.1.1") profile = WebProfile.safari_ipad() profile = WebProfile.firefox("latest") profile = WebProfile.edge("latest") profile = WebProfile.okhttp("5") profile = WebProfile.none() spec = profile.spec() ``` Use `profile.spec()` as the persistent selector string. ## Client Capabilities `Client` exposes these subclients and helpers: - `client.dm`: direct messages. - `client.upload`: media upload and metadata. - `client.inbox`: inbox updates, conversations, counts. - `client.user`: profile, follow graph, follow/block/list helpers. - `client.posts`: create/delete/like/retweet/timeline helpers. `create_retweet` = pure Repost only (no promoted engagement fields; Quote uses create_tweet quote). `delete_retweet` needs original tweet_id; success requires unretweet result path, not HTTP 200 alone — always check `ApiResult.success` / `error_msg`. - `client.communities`: community search and join. - `client.settings`: account, search safety, audience, explore settings. - `client.search`: top/latest/people/media/list search. - `client.xchat(keystore_path)`: XChat E2E DM client using a keystore file. - `client.xchat_from_environment()`: XChat client restored from snapshot key material. - `client.raw_get(url, params=None)` and `client.raw_post(url, params=None, body=None)`: authenticated raw HTTP helpers. - `client.validate_cookies()`, `client.get_cookies()`, `client.fingerprint_info()`. - `client.export_environment()`, `client.export_environment_json()`, `Client.restore_environment(snapshot)`, `Client.restore_environment_json(snapshot_json)`. - `Client.auth_token_to_cookies(auth_token, proxy_url=None)`: staticmethod, returns `AuthTokenResult` (see Auth Token To Cookies). ## Result Model Most Python API calls return `ApiResult`. ```python result = await client.dm.send_message("123", "hello") data = result.to_dict() json_text = result.to_json() event_id = result.event_id # attribute access maps JSON object fields ``` `ApiResult` fields depend on the API response. Use `to_dict()` when generating robust code. ## Minimal Examples ```python result = await client.dm.send_message("123", "hello", media_id=None) upload = await client.upload.upload_file("image.jpg", category="tweet_image") tweet = await client.posts.create_tweet(text="hello", media_ids=[upload.media_id_string]) profile = await client.user.get_profile("x") search = await client.search.search_latest("open source") ``` ## Environment Snapshot ```python snapshot_json = client.export_environment_json() restored = Client.restore_environment_json(snapshot_json) snapshot_dict = client.export_environment().to_dict() restored = Client.restore_environment(snapshot_dict) ``` Environment snapshots are plaintext sensitive data. They can contain cookies, CSRF/auth tokens, proxy/profile/header policy, ClientTransaction material, and optional XChat key material. Encrypt snapshots before database storage and never log them. ## XChat ```python xchat = client.xchat("/path/to/keystore.json") await xchat.enroll(pin) await xchat.status() await xchat.send_message("123", "encrypted hello") ``` Use `client.xchat_from_environment()` only when the restored environment snapshot contains XChat key material. ## Source Of Truth - Runtime binding: `src/py/src/**` - Public exports: `python/x_api_rs/__init__.py`, `python/x_api_rs/web/__init__.py` - Type contract: `python/x_api_rs/x_api_rs.pyi` - Full AI reference: `docs/python/llms-full.txt`