{"id":21977314,"url":"https://github.com/iwatkot/py3xui","last_synced_at":"2025-04-04T11:07:17.423Z","repository":{"id":245404948,"uuid":"815704235","full_name":"iwatkot/py3xui","owner":"iwatkot","description":"Sync and Async Object-oriented Python SDK for the 3x-ui API.","archived":false,"fork":false,"pushed_at":"2025-03-13T09:06:14.000Z","size":158,"stargazers_count":85,"open_issues_count":0,"forks_count":12,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-28T10:01:40.829Z","etag":null,"topics":["3x-ui","api","async","httpx","mypy","pydantic","pylint","pytest","python","requests","sdk","vless","vpn","x-ui"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/iwatkot.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":null,"patreon":null,"open_collective":null,"ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"lfx_crowdfunding":null,"polar":null,"buy_me_a_coffee":"iwatkot0","thanks_dev":null,"custom":null}},"created_at":"2024-06-15T22:24:15.000Z","updated_at":"2025-03-26T19:41:51.000Z","dependencies_parsed_at":"2024-09-06T18:10:33.163Z","dependency_job_id":"788e0dc7-4acb-41c6-bb76-268853610757","html_url":"https://github.com/iwatkot/py3xui","commit_stats":null,"previous_names":["iwatkot/py3xui"],"tags_count":19,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/iwatkot%2Fpy3xui","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/iwatkot%2Fpy3xui/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/iwatkot%2Fpy3xui/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/iwatkot%2Fpy3xui/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/iwatkot","download_url":"https://codeload.github.com/iwatkot/py3xui/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247159823,"owners_count":20893692,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["3x-ui","api","async","httpx","mypy","pydantic","pylint","pytest","python","requests","sdk","vless","vpn","x-ui"],"created_at":"2024-11-29T16:14:16.718Z","updated_at":"2025-04-04T11:07:17.395Z","avatar_url":"https://github.com/iwatkot.png","language":"Python","funding_links":["https://buymeacoffee.com/iwatkot0"],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\" markdown\u003e\n\u003cimg src=\"https://github.com/iwatkot/py3xui/assets/118521851/42c5d579-6202-4a9e-88f3-2d844fdd95b6\"\u003e\n\nSync and Async Object-oriented Python SDK for the 3x-ui API.\n\n\u003cp align=\"center\"\u003e\n    \u003ca href=\"#Overview\"\u003eOverview\u003c/a\u003e •\n    \u003ca href=\"#Quick-Start\"\u003eQuick Start\u003c/a\u003e •\n    \u003ca href=\"#Examples\"\u003eExamples\u003c/a\u003e •\n    \u003ca href=\"#Bugs-and-Feature-Requests\"\u003eBugs and Feature Requests\u003c/a\u003e •\n    \u003ca href=\"https://pypi.org/project/py3xui/\"\u003ePyPI\u003c/a\u003e\n\u003c/p\u003e\n\n[![GitHub release (latest SemVer)](https://img.shields.io/github/v/release/iwatkot/py3xui)](https://github.com/iwatkot/py3xui/releases)\n[![GitHub issues](https://img.shields.io/github/issues/iwatkot/py3xui)](https://github.com/iwatkot/py3xui/issues)\n[![Build Status](https://github.com/iwatkot/py3xui/actions/workflows/checks.yml/badge.svg)](https://github.com/iwatkot/py3xui/actions)\n[![Checked with mypy](https://www.mypy-lang.org/static/mypy_badge.svg)](https://mypy-lang.org/)\n[![PyPI - Downloads](https://img.shields.io/pypi/dm/py3xui)](https://pypi.org/project/py3xui/)\u003cbr\u003e\n[![PyPI - Python Version](https://img.shields.io/pypi/pyversions/py3xui)](https://pypi.org/project/py3xui/)\n[![PyPI - Version](https://img.shields.io/pypi/v/py3xui)](https://pypi.org/project/py3xui/)\n[![Maintainability](https://api.codeclimate.com/v1/badges/c03ca2bca0191cb4a2ae/maintainability)](https://codeclimate.com/github/iwatkot/py3xui/maintainability)\n[![Test Coverage](https://api.codeclimate.com/v1/badges/c03ca2bca0191cb4a2ae/test_coverage)](https://codeclimate.com/github/iwatkot/py3xui/test_coverage)\n\n\u003c/div\u003e\n\n## Overview\nThis SDK is designed to interact with the [3x-ui](https://github.com/MHSanaei/3x-ui) app in a more object-oriented way. It provides both synchronous and asynchronous methods to interact with the app. The SDK is designed to be as simple as possible to use, while still providing a lot of flexibility and uses `Pydantic` models to validate the data.\u003cbr\u003e\nUsed dependencies:\n- `requests` for synchronous API\n- `httpx` for asynchronous API\n- `pydantic` for models\n\nSupported Python versions:\n- 3.11\n- 3.12\n\nSince the 3x-ui app is under development, the SDK may not be compatible with all versions of the app. The developer of SDK is not related to the 3x-ui app, therefore the latest versions of the software are not guaranteed to be compatible with the SDK. \u003cbr\u003e\nThe SDK does not support versions of the 3x-ui older than `2.3.7`.\n\n## Quick Start\nYou can use both synchronous and asynchronous methods to interact with the 3x-ui app. Both APIs have the same methods and return the same data, so it's up to you to choose which one to use.\u003cbr\u003e\nAfter installing the SDK, you can create a new instance of the API. When creating a new instance, you can either use environment variables or pass the credentials directly. It's strongly recommended to use environment variables to store the API credentials.\u003cbr\u003e\nOn creation, the Api won't connect to the 3x-ui app, so you can spawn new instances without spending resources. But after creating an instance, you'll need to call the `login` method to authenticate the user and save the cookie for future requests.\n\n### Installation\n```bash\npip install py3xui\n```\n\n### Create a new instance of the SDK\nIt's recommended to use an environment variable to store the API credentials:\n```python\nimport os\n\nos.environ[\"XUI_HOST\"] = \"http://your-3x-ui-host.com:2053\"\nos.environ[\"XUI_USERNAME\"] = \"your-username\"\nos.environ[\"XUI_PASSWORD\"] = \"your-password\"\n```\n\nTo work synchronously:\n```python\nfrom py3xui import Api\n\n# Using environment variables:\napi = Api.from_env()\n\n# Or using the credentials directly:\napi = Api(\"http://your-3x-ui-host.com:2053\", \"your-username\", \"your-password\")\n```\n\nTo work asynchronously:\n```python\nfrom py3xui import AsyncApi\n\n# Using environment variables:\napi = AsyncApi.from_env()\n\n# Or using the credentials directly:\napi = AsyncApi(\"http://your-3x-ui-host.com:2053\", \"your-username\", \"your-password\")\n```\n\n*️⃣ If you're using a custom URI Path, ensure that you've added it to the host, for example:\u003cbr\u003e\nIf your host is `http://your-3x-ui-host.com:2053` and the URI Path is `/test/`, then the host should be `http://your-3x-ui-host.com:2053/test/`.\u003cbr\u003e\nOtherwise, all API requests will fail with a `404` error.\n\n*️⃣ If you're using a secret token, which is set in in the 3x-ui panel, you'll also add it, otherwise all API request will fail.\u003cbr\u003e\nSame as for other credentials, you can use an environment variable to store the token:\n```python\n...\nos.environ[\"XUI_TOKEN\"] = \"your-token\"\n\napi = Api.from_env()\n```\n\nOr pass it directly, when creating an instance:\n```python\napi = Api(\"http://your-3x-ui-host.com:2053\", \"your-username\", \"your-password\", \"your-token\")\n```\n\n### Using TLS and custom certificates\nInteracting with server over HTTPS requires careful management of TLS verification to ensure secure communications. This SDK provides options for setting TLS configurations, which include specifying custom certificates for increased trust or disabling TLS verification when necessary.\n\n#### Case 1: Disabling TLS verification\nFor development, you can disable TLS verification. This is not recommended for production due to the increased risk of security threats like man-in-the-middle attacks.\n```python\napi = Api(\"http://your-3x-ui-host.com:2053\", \"your-username\", \"your-password\", use_tls_verify=False)\n```\n❗ Warning: Never disable TLS verification in production.\n\n#### Case 2: Using сustom сertificates\nIf you are interacting with a server that uses a self-signed certificate or one not recognized by the standard CA bundle, you can specify a custom certificate path:\n```python\napi = Api(\n    \"http://your-3x-ui-host.com:2053\",\n    \"your-username\",\n    \"your-password\",\n    custom_certificate_path=\"/path/to/your/certificate.pem\",\n)\n```\nThis allows you to maintain TLS verification by providing a trusted certificate explicitly.\n\n### Login\nNo matter which API you're using or if was it created using environment variables or credentials, you'll need to call the `login` method to authenticate the user and save the cookie for future requests.\n```python\nfrom py3xui import Api, AsyncApi\n\napi = Api.from_env()\napi.login()\n\nasync_api = AsyncApi.from_env()\nawait async_api.login()\n```\n\n## Examples\nYou'll find detailed docs with usage examples for both APIs and for used models in the corresponding package directories:\n- [Synchronous API](py3xui/api/README.md)\n- [Asynchronous API](py3xui/async_api/README.md)\n- [Client](py3xui/client/README.md)\n- [Inbound](py3xui/inbound/README.md)\n\nIn this section, you'll find some examples of how to use the SDK. In the examples, we'll use the synchronous API, but you can use the asynchronous API in the same way, just remember to use `await` before calling the methods.\u003cbr\u003e\n\n### Set the traffic limit for the client\nℹ️ You'll also find this example in the [demo.py](demo.py) file.\n\n```python\nfrom py3xui import Api\n\n# 1️⃣ Create an instance of the API class.\nhost = \"**************************\"\nusername = \"**********\"\npassword = \"**********\"\napi = Api(host, username, password)\n\n# 2️⃣ Login to the API.\napi.login()\n\nuser_email = \"iwatkot\"  # ⬅️ Your user email here.\ninbound_id = 4  # ⬅️ Your inbound ID here.\n\n# 3️⃣ Get the inbound.\ninbound = api.inbound.get_by_id(inbound_id)\nprint(f\"Inbound has {len(inbound.settings.clients)} clients\")\n\n# 4️⃣ Find the needed client in the inbound.\nclient = None\nfor c in inbound.settings.clients:\n    if c.email == user_email:\n        client = c\n        break\n\nif client:\n    print(f\"Found client with ID: {client.id}\")  # ⬅️ The actual Client UUID.\nelse:\n    raise ValueError(f\"Client with email {user_email} not found\")\n\ncliend_uuid = client.id\n\n# 5️⃣ Get the client by email.\nclient_by_email = api.client.get_by_email(user_email)\nprint(f\"Client by email has ID: {client_by_email.id}\")  # ⬅️ The numeric ID here.\n\n# 6️⃣ Update the client with needed parameters.\nclient_by_email.total_gb = 1000 * 1024 * 1024  # ⬅️ Your value here.\n\n# 7️⃣ Update the client ID so it will be UUID, not numeric.\nclient_by_email.id = cliend_uuid\n\n# 8️⃣ Update the client.\napi.client.update(client_by_email.id, client_by_email)\n```\n\n### Create a connection string and QR code\nWhen you need to provide the user with a connection string that can be used in a software to create a new connection profile and/or a QR code, you can use the following example.\n\n```python\nfrom py3xui import Inbound\n\nXUI_EXTERNAL_IP = \"**********\"  # ⬅️ Your external IP here or domain name.\nMAIN_REMARK = \"gmfvbot\"  # ⬅️ It can be any string.\nSERVER_PORT = 443  # ⬅️ Your server port here.\n\n\ndef get_connection_string(inbound: Inbound, user_uuid: str, user_email: int) -\u003e str:\n    \"\"\"Prepare a connection string for the given inbound, user UUID and telegram ID.\n\n    Arguments:\n        inbound (Inbound): The inbound object.\n        user_uuid (str): The UUID of the user.\n        user_email (int): The email of the user.\n\n    Returns:\n        str: The connection string.\n    \"\"\"\n    public_key = inbound.stream_settings.reality_settings.get(\"settings\").get(\"publicKey\")\n    website_name = inbound.stream_settings.reality_settings.get(\"serverNames\")[0]\n    short_id = inbound.stream_settings.reality_settings.get(\"shortIds\")[0]\n\n    connection_string = (\n        f\"vless://{user_uuid}@{XUI_EXTERNAL_IP}:{SERVER_PORT}\"\n        f\"?type=tcp\u0026security=reality\u0026pbk={public_key}\u0026fp=firefox\u0026sni={website_name}\"\n        f\"\u0026sid={short_id}\u0026spx=%2F#{MAIN_REMARK}-{user_email}\"\n    )\n\n    return connection_string\n```\n\nAnd how, when you have the connection string, you can use the `qrcode` library to generate a QR code:\n\n```bash\npip install qrcode\n```\n\n```python\nimport os\n\nimport qrcode\n\n# 1️⃣ Obtain the connection string.\nuser_email = \"iwatkot\"  # ⬅️ Your user email here.\nconnection_string = get_connection_string(inbound, \"**********\", user_email)\n\n# 2️⃣ Create the QR code.\nimg = qrcode.make(connection_string)\n\n# 3️⃣ Save the QR code to the file.\nqrcode_path = os.path.join(\"qrcodes\", f\"{user_email}.png\")\nimg.save(qrcode_path)\n\n# Now you can use the `qrcode_path` to send the QR code to the user.\n```\n\n\n### Get inbounds list\n```python\nfrom py3xui import Api, Inbound\n\napi = Api.from_env()\napi.login()\ninbounds: List[Inbound] = api.inbound.get_list()\n```\n\n### Add a new inbound\n```python\nfrom py3xui import Api\nfrom py3xui.inbound import Inbound, Settings, Sniffing, StreamSettings\n\napi = Api.from_env()\napi.login()\n\nsettings = Settings()\nsniffing = Sniffing(enabled=True)\n\ntcp_settings = {\n    \"acceptProxyProtocol\": False,\n    \"header\": {\"type\": \"none\"},\n}\nstream_settings = StreamSettings(security=\"reality\", network=\"tcp\", tcp_settings=tcp_settings)\n\ninbound = Inbound(\n    enable=True,\n    port=443,\n    protocol=\"vless\",\n    settings=settings,\n    stream_settings=stream_settings,\n    sniffing=sniffing,\n    remark=\"test3\",\n)\n\napi.inbound.add(inbound)\n```\n\n### Get a client by email\n```python\nfrom py3xui import Api, Client\n\napi = Api.from_env()\napi.login()\n\nclient: Client = api.client.get_by_email(\"some-email\")\n```\n\n### Add a new client\n```python\nfrom py3xui import Api, Client\n\napi = Api.from_env()\napi.login()\n\nnew_client = Client(id=str(uuid.uuid4()), email=\"test\", enable=True)\ninbound_id = 1\n\napi.client.add(inbound_id, [new_client])\n```\n\n## Bugs and Feature Requests\nIf you find a bug or have a feature request, please open an issue on the GitHub repository.\u003cbr\u003e\nYou're also welcome to contribute to the project by opening a pull request.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fiwatkot%2Fpy3xui","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fiwatkot%2Fpy3xui","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fiwatkot%2Fpy3xui/lists"}