mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2025-08-23 11:26:52 +00:00
366 lines
14 KiB
Markdown
366 lines
14 KiB
Markdown
![]() |
# X-UI API Documentation
|
||
|
|
||
|
## Overview
|
||
|
|
||
|
This document provides instructions for interacting with the X-UI panel API. The API allows for programmatic management of inbounds (connections), users, and server settings.
|
||
|
|
||
|
### Authentication
|
||
|
|
||
|
The API uses a **cookie-based session** for authentication.
|
||
|
|
||
|
1. You must first send a `POST` request to the `/login` endpoint with your credentials.
|
||
|
2. If successful, the server will respond with a `Set-Cookie` header containing a session cookie (e.g., `session=...`).
|
||
|
3. Your HTTP client **must** store this cookie and include it in the `Cookie` header for all subsequent API requests.
|
||
|
|
||
|
While many headers sent by a browser are not strictly required, including a `User-Agent` and `Referer` is good practice to better emulate a real client.
|
||
|
|
||
|
## Endpoints
|
||
|
|
||
|
### 1. Login
|
||
|
|
||
|
Authenticates the user and initiates a session by returning a session cookie.
|
||
|
|
||
|
* **Endpoint:** `POST {base_url}/login`
|
||
|
* **Body:** `application/x-www-form-urlencoded`
|
||
|
|
||
|
| Parameter | Type | Description |
|
||
|
| :--------- | :----- | :--------------------- |
|
||
|
| `username` | string | Your panel username. |
|
||
|
| `password` | string | Your panel password. |
|
||
|
|
||
|
* **Success Response (200 OK):**
|
||
|
* The response will include a `Set-Cookie` header in the HTTP response.
|
||
|
```json
|
||
|
{
|
||
|
"success": true,
|
||
|
"msg": "Login successful",
|
||
|
"obj": null
|
||
|
}
|
||
|
```
|
||
|
|
||
|
### 2. Get All Inbounds
|
||
|
|
||
|
Fetches a list of all configured inbound connections.
|
||
|
|
||
|
* **Endpoint:** `POST {base_url}/panel/inbound/list`
|
||
|
* **Body:** None
|
||
|
* **Success Response (200 OK):**
|
||
|
|
||
|
```json
|
||
|
{
|
||
|
"success": true,
|
||
|
"msg": "",
|
||
|
"obj": [
|
||
|
{
|
||
|
"id": 1,
|
||
|
"up": 40912424334,
|
||
|
"down": 537061968966,
|
||
|
"total": 0,
|
||
|
"remark": "My-First-Inbound",
|
||
|
"enable": true,
|
||
|
"expiryTime": 0,
|
||
|
"listen": "YOUR_SERVER_IP",
|
||
|
"port": 19271,
|
||
|
"protocol": "vless",
|
||
|
"settings": "{\"clients\":[{\"id\":\"user-uuid-goes-here\",\"email\":\"user-email-goes-here\",...}]}",
|
||
|
"streamSettings": "{\"network\":\"tcp\",\"security\":\"reality\",\"realitySettings\":{\"privateKey\":\"REALITY_PRIVATE_KEY\",\"settings\":{\"publicKey\":\"REALITY_PUBLIC_KEY\"},...}}",
|
||
|
"tag": "inbound-YOUR_SERVER_IP:19271",
|
||
|
"sniffing": "{\"enabled\":false,...}"
|
||
|
}
|
||
|
]
|
||
|
}
|
||
|
```
|
||
|
|
||
|
### 3. Get Online Clients
|
||
|
|
||
|
Fetches a list of emails corresponding to currently online clients.
|
||
|
|
||
|
* **Endpoint:** `POST {base_url}/panel/inbound/onlines`
|
||
|
* **Body:** None
|
||
|
* **Success Response (200 OK):**
|
||
|
```json
|
||
|
{
|
||
|
"success": true,
|
||
|
"msg": "",
|
||
|
"obj": [
|
||
|
"client1-email",
|
||
|
"online-user@example.com"
|
||
|
]
|
||
|
}
|
||
|
```
|
||
|
|
||
|
### 4. Get New Reality Certificate
|
||
|
|
||
|
Generates a new X25519 key pair for use with VLESS Reality.
|
||
|
|
||
|
* **Endpoint:** `POST {base_url}/server/getNewX25519Cert`
|
||
|
* **Body:** None
|
||
|
* **Success Response (200 OK):**
|
||
|
```json
|
||
|
{
|
||
|
"success": true,
|
||
|
"msg": "",
|
||
|
"obj": {
|
||
|
"privateKey": "a_very_long_private_key_string",
|
||
|
"publicKey": "a_shorter_public_key_string"
|
||
|
}
|
||
|
}
|
||
|
```
|
||
|
|
||
|
### 5. Add VLESS Reality Inbound
|
||
|
|
||
|
Creates a new VLESS Reality inbound connection.
|
||
|
|
||
|
* **Endpoint:** `POST {base_url}/panel/inbound/add`
|
||
|
* **Body:** `application/x-www-form-urlencoded`
|
||
|
|
||
|
This endpoint requires a complex body where several parameters are URL-encoded JSON strings.
|
||
|
|
||
|
| Parameter | Description | Example Value |
|
||
|
| :--------------- | :------------------------------------------------------------------------------ | :--------------------------------------------- |
|
||
|
| `remark` | A name or comment for the inbound. | `My-Test-Key` |
|
||
|
| `listen` | The server IP address to listen on. Leave empty for all IPs. | `YOUR_SERVER_IP` |
|
||
|
| `port` | The port to listen on. `0` for a random port. | `48673` |
|
||
|
| `protocol` | The protocol type. | `vless` |
|
||
|
| `expiryTime` | Expiration timestamp in milliseconds. `0` for no expiration. | `1753969593148` |
|
||
|
| `total` | Data limit in bytes. `0` for unlimited. | `0` |
|
||
|
| `settings` | URL-encoded JSON string with client details (UUID, email, etc.). | (See structure below) |
|
||
|
| `streamSettings` | URL-encoded JSON string with transport and security settings (e.g., Reality). | (See structure below) |
|
||
|
| `sniffing` | URL-encoded JSON string for traffic sniffing settings. | `{"enabled":false,...}` |
|
||
|
|
||
|
* **Decoded `settings` Structure:**
|
||
|
```json
|
||
|
{
|
||
|
"clients": [
|
||
|
{
|
||
|
"id": "a-generated-uuid",
|
||
|
"email": "a-generated-email",
|
||
|
"enable": true,
|
||
|
"flow": "",
|
||
|
"limitIp": 0,
|
||
|
"totalGB": 0,
|
||
|
"expiryTime": 0,
|
||
|
"subId": "a-generated-sub-id"
|
||
|
}
|
||
|
],
|
||
|
"decryption": "none",
|
||
|
"fallbacks": []
|
||
|
}
|
||
|
```
|
||
|
* **Decoded `streamSettings` Structure:**
|
||
|
```json
|
||
|
{
|
||
|
"network": "tcp",
|
||
|
"security": "reality",
|
||
|
"realitySettings": {
|
||
|
"dest": "example.com:443",
|
||
|
"serverNames": ["example.com", "www.example.com"],
|
||
|
"privateKey": "THE_PRIVATE_KEY_FROM_STEP_4",
|
||
|
"publicKey": "THE_PUBLIC_KEY_FROM_STEP_4",
|
||
|
"shortIds": ["generated_id1", "generated_id2"],
|
||
|
"fingerprint": "chrome",
|
||
|
"spiderX": "/"
|
||
|
}
|
||
|
}
|
||
|
```
|
||
|
|
||
|
* **Success Response (200 OK):** The response object contains the full configuration of the newly created inbound.
|
||
|
```json
|
||
|
{
|
||
|
"success": true,
|
||
|
"msg": "Create Successfully",
|
||
|
"obj": {
|
||
|
"id": 16,
|
||
|
"remark": "Test test",
|
||
|
"port": 48673,
|
||
|
"listen": "YOUR_SERVER_IP",
|
||
|
"settings": "{\"clients\":[{\"id\":\"60f3a042-7f0c-43a5-a9e6-de76f66703dd\",...}]}",
|
||
|
"streamSettings": "{\"network\":\"tcp\",\"security\":\"reality\",\"realitySettings\":{...}}",
|
||
|
// ... and other fields
|
||
|
}
|
||
|
}
|
||
|
```
|
||
|
|
||
|
## Code Examples
|
||
|
|
||
|
### Python (`requests`)
|
||
|
|
||
|
The `requests.Session` object is perfect for this task as it automatically handles cookies across requests.
|
||
|
|
||
|
```python
|
||
|
import requests
|
||
|
|
||
|
# --- Configuration ---
|
||
|
BASE_URL = "http://127.0.0.1:PORT/YOUR_SECRET_PATH"
|
||
|
USERNAME = "your_username"
|
||
|
PASSWORD = "your_password"
|
||
|
|
||
|
# 1. Create a session that will store cookies
|
||
|
session = requests.Session()
|
||
|
|
||
|
# 2. Login to establish the session
|
||
|
try:
|
||
|
login_url = f"{BASE_URL}/login"
|
||
|
login_data = {"username": USERNAME, "password": PASSWORD}
|
||
|
response = session.post(login_url, data=login_data)
|
||
|
response.raise_for_status()
|
||
|
|
||
|
if response.json().get("success"):
|
||
|
print("Login successful!")
|
||
|
|
||
|
# 3. Now you can make other API calls with the same session
|
||
|
inbounds_url = f"{BASE_URL}/panel/inbound/list"
|
||
|
inbounds_response = session.post(inbounds_url)
|
||
|
inbounds_data = inbounds_response.json()
|
||
|
|
||
|
print(f"Successfully fetched {len(inbounds_data.get('obj', []))} inbounds.")
|
||
|
else:
|
||
|
print(f"Login failed: {response.json().get('msg')}")
|
||
|
|
||
|
except requests.exceptions.RequestException as e:
|
||
|
print(f"An error occurred: {e}")
|
||
|
```
|
||
|
|
||
|
### Node.js (`axios`)
|
||
|
|
||
|
In Node.js, `axios` does not handle cookies by default. You need to use a cookie jar helper library like `axios-cookiejar-support` and `tough-cookie`.
|
||
|
|
||
|
First, install the dependencies:
|
||
|
`npm install axios axios-cookiejar-support tough-cookie`
|
||
|
|
||
|
```javascript
|
||
|
const axios = require('axios');
|
||
|
const { HttpsCookieAgent } = require('http-cookie-agent/http');
|
||
|
const tough = require('tough-cookie');
|
||
|
|
||
|
// --- Configuration ---
|
||
|
const BASE_URL = 'http://127.0.0.1:PORT/YOUR_SECRET_PATH';
|
||
|
const USERNAME = 'your_username';
|
||
|
const PASSWORD = 'your_password';
|
||
|
|
||
|
async function main() {
|
||
|
// 1. Create a cookie jar to store session cookies
|
||
|
const cookieJar = new tough.CookieJar();
|
||
|
|
||
|
// 2. Create an axios instance that uses the cookie jar
|
||
|
const apiClient = axios.create({
|
||
|
httpAgent: new HttpsCookieAgent({ cookies: { jar: cookieJar } }),
|
||
|
httpsAgent: new HttpsCookieAgent({ cookies: { jar: cookieJar } }),
|
||
|
});
|
||
|
|
||
|
try {
|
||
|
// 3. Login
|
||
|
console.log('Attempting to log in...');
|
||
|
const loginUrl = `${BASE_URL}/login`;
|
||
|
// For x-www-form-urlencoded, use a URLSearchParams object
|
||
|
const loginData = new URLSearchParams({
|
||
|
username: USERNAME,
|
||
|
password: PASSWORD
|
||
|
});
|
||
|
|
||
|
const loginResponse = await apiClient.post(loginUrl, loginData);
|
||
|
|
||
|
if (loginResponse.data.success) {
|
||
|
console.log('Login successful!');
|
||
|
|
||
|
// 4. Make another request. The cookie is sent automatically.
|
||
|
const inboundsUrl = `${BASE_URL}/panel/inbound/list`;
|
||
|
const inboundsResponse = await apiClient.post(inboundsUrl);
|
||
|
|
||
|
if (inboundsResponse.data.success) {
|
||
|
console.log(`Successfully fetched ${inboundsResponse.data.obj.length} inbounds.`);
|
||
|
} else {
|
||
|
console.error('Failed to fetch inbounds:', inboundsResponse.data.msg);
|
||
|
}
|
||
|
} else {
|
||
|
console.error('Login failed:', loginResponse.data.msg);
|
||
|
}
|
||
|
} catch (error) {
|
||
|
console.error('An API error occurred:', error.message);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
main();
|
||
|
```
|
||
|
|
||
|
### Browser JavaScript (`fetch`)
|
||
|
|
||
|
In a web browser context, `fetch` can automatically handle cookies if the request is to the same origin, or if you specify `credentials: 'include'` for cross-origin requests.
|
||
|
|
||
|
```javascript
|
||
|
// --- Configuration ---
|
||
|
const BASE_URL = 'http://127.0.0.1:PORT/YOUR_SECRET_PATH';
|
||
|
const USERNAME = 'your_username';
|
||
|
const PASSWORD = 'your_password';
|
||
|
|
||
|
async function runApiFlow() {
|
||
|
try {
|
||
|
// 1. Login
|
||
|
console.log('Logging in...');
|
||
|
const loginResponse = await fetch(`${BASE_URL}/login`, {
|
||
|
method: 'POST',
|
||
|
headers: {
|
||
|
'Content-Type': 'application/x-www-form-urlencoded',
|
||
|
},
|
||
|
body: new URLSearchParams({
|
||
|
username: USERNAME,
|
||
|
password: PASSWORD
|
||
|
}),
|
||
|
// This is crucial for the browser to store and send cookies
|
||
|
credentials: 'include'
|
||
|
});
|
||
|
|
||
|
const loginResult = await loginResponse.json();
|
||
|
if (!loginResult.success) {
|
||
|
throw new Error(`Login failed: ${loginResult.msg}`);
|
||
|
}
|
||
|
console.log('Login successful!');
|
||
|
|
||
|
// 2. Fetch inbounds. The browser automatically includes the cookie.
|
||
|
const inboundsResponse = await fetch(`${BASE_URL}/panel/inbound/list`, {
|
||
|
method: 'POST',
|
||
|
credentials: 'include'
|
||
|
});
|
||
|
|
||
|
const inboundsResult = await inboundsResponse.json();
|
||
|
if (inboundsResult.success) {
|
||
|
console.log(`Found ${inboundsResult.obj.length} inbounds.`);
|
||
|
} else {
|
||
|
throw new Error(`Failed to fetch inbounds: ${inboundsResult.msg}`);
|
||
|
}
|
||
|
|
||
|
} catch (error) {
|
||
|
console.error('API Flow Error:', error);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
runApiFlow();
|
||
|
```
|
||
|
|
||
|
## Generating the VLESS URL
|
||
|
|
||
|
After creating an inbound using the `/panel/inbound/add` endpoint, you can construct a standard `vless://` URL from the `obj` field in the JSON response.
|
||
|
|
||
|
The URL format is:
|
||
|
`vless://{UUID}@{ADDRESS}:{PORT}?{PARAMETERS}#{REMARK}`
|
||
|
|
||
|
Here is how to map the JSON response fields to the URL components:
|
||
|
|
||
|
| URL Part | JSON Path from `obj` | Example |
|
||
|
| :---------- | :-------------------------------------------------------------- | :---------------------------------------------- |
|
||
|
| `UUID` | `settings.clients[0].id` (after JSON parsing) | `60f3a042-7f0c-43a5-a9e6-de76f66703dd` |
|
||
|
| `ADDRESS` | `listen` (or your server's domain name) | `YOUR_SERVER_IP` |
|
||
|
| `PORT` | `port` | `48673` |
|
||
|
| `REMARK` | `remark` (URL-encoded) | `Test%20test` |
|
||
|
|
||
|
**Parameters (in the query string):**
|
||
|
|
||
|
| Parameter | JSON Path from `obj` | Description |
|
||
|
| :-------- | :-------------------------------------------------------------- | :---------------------------------------------- |
|
||
|
| `type` | `streamSettings.network` | Transport protocol, e.g., `tcp`. |
|
||
|
| `security` | `streamSettings.security` | Security layer, e.g., `reality`. |
|
||
|
| `pbk` | `streamSettings.realitySettings.settings.publicKey` | The public key for Reality. |
|
||
|
| `fp` | `streamSettings.realitySettings.settings.fingerprint` | The browser fingerprint, e.g., `chrome`. |
|
||
|
| `sni` | `streamSettings.realitySettings.serverNames[0]` | The Server Name Indication to use. |
|
||
|
| `sid` | `streamSettings.realitySettings.shortIds[0]` | The first short ID from the list. |
|
||
|
| `spx` | `streamSettings.realitySettings.settings.spiderX` | The SpiderX path. |
|