diff --git a/docs/categories/03-line-api.md b/docs/categories/03-line-api.md new file mode 100644 index 0000000..bc823f9 --- /dev/null +++ b/docs/categories/03-line-api.md @@ -0,0 +1,962 @@ +# Line API - Subscription Management + +Complete documentation for subscription line management in the XUI.ONE Admin API. + +## 📋 Overview + +The Line API provides complete control over subscription lines (M3U/Xtream Codes accounts). You can create, modify, enable, disable, and delete subscription lines programmatically. + +### Available Operations + +| Operation | Action | Method | Description | +|-----------|--------|--------|-------------| +| **View** | `get_line` | GET | Get specific line details | +| **Create** | `create_line` | POST | Create new subscription | +| **Update** | `edit_line` | POST | Modify existing line | +| **Delete** | `delete_line` | POST | Permanently remove line | +| **Enable** | `enable_line` | POST | Activate disabled line | +| **Disable** | `disable_line` | POST | Temporarily suspend line | +| **Ban** | `ban_line` | POST | Block abusive account | +| **Unban** | `unban_line` | POST | Remove ban from line | + +--- + +## 🔍 Get Specific Line + +### Action: `get_line` + +Retrieve detailed information about a specific subscription line. + +**Parameters:** +- `id` (required) - Line ID + +**Request:** +```bash +curl "http://your-server.com/cSbuFLhp/?api_key=8D3135D30437F86EAE2FA4A2A8345000&action=get_line&id=123" +``` + +**Response:** +```json +{ + "status": "STATUS_SUCCESS", + "data": { + "id": "123", + "username": "testuser", + "password": "testpass123", + "exp_date": "1735689600", + "max_connections": "1", + "is_trial": "0", + "enabled": "1", + "is_restreamer": "0", + "bouquet": "[1,2,3]", + "notes": "Premium customer", + "created_at": "1609459200" + } +} +``` + +--- + +## ➕ Create New Line + +### Action: `create_line` + +Create a new subscription line with specified settings. + +**Required Parameters:** +- `username` - Username for the line +- `password` - Password for the line + +**Optional Parameters:** +- `max_connections` - Maximum concurrent connections (default: 1) +- `exp_date` - Expiration date (YYYY-MM-DD, timestamp, or relative like "1month") +- `is_trial` - Trial status (0 = No, 1 = Yes) +- `is_restreamer` - Reseller status (0 = No, 1 = Yes) +- `bouquets_selected[]` - Array of bouquet/package IDs +- `notes` - Admin notes +- `contact` - Contact information +- `isp_lock` - Lock to specific IP address + +**Request:** +```bash +curl -X POST "http://your-server.com/cSbuFLhp/?api_key=8D3135D30437F86EAE2FA4A2A8345000&action=create_line" \ + -d "username=newuser" \ + -d "password=securepass123" \ + -d "max_connections=1" \ + -d "exp_date=2025-12-31" \ + -d "bouquets_selected[]=1" \ + -d "bouquets_selected[]=2" \ + -d "notes=Premium customer" +``` + +**Response:** +```json +{ + "status": "STATUS_SUCCESS", + "data": { + "line_id": "456", + "username": "newuser", + "password": "securepass123" + } +} +``` + +--- + +## ✏️ Edit Existing Line + +### Action: `edit_line` + +Modify settings of an existing subscription line. + +**Required Parameters:** +- `id` - Line ID to edit + +**Optional Parameters:** +- `username` - New username +- `password` - New password +- `max_connections` - Update connection limit +- `exp_date` - Update expiration date +- `is_trial` - Update trial status +- `bouquets_selected[]` - Update assigned packages +- `notes` - Update notes + +**Request:** +```bash +curl -X POST "http://your-server.com/cSbuFLhp/?api_key=8D3135D30437F86EAE2FA4A2A8345000&action=edit_line" \ + -d "id=123" \ + -d "password=newpassword456" \ + -d "max_connections=2" \ + -d "exp_date=2026-06-30" +``` + +**Response:** +```json +{ + "status": "STATUS_SUCCESS", + "data": { + "message": "Line updated successfully" + } +} +``` + +--- + +## 🗑️ Delete Line + +### Action: `delete_line` + +Permanently remove a subscription line from the panel. + +⚠️ **Warning:** This action cannot be undone! + +**Required Parameters:** +- `id` - Line ID to delete + +**Request:** +```bash +curl -X POST "http://your-server.com/cSbuFLhp/?api_key=8D3135D30437F86EAE2FA4A2A8345000&action=delete_line" \ + -d "id=123" +``` + +**Response:** +```json +{ + "status": "STATUS_SUCCESS", + "data": { + "message": "Line deleted successfully" + } +} +``` + +--- + +## ✅ Enable Line + +### Action: `enable_line` + +Activate a previously disabled line. + +**Required Parameters:** +- `id` - Line ID to enable + +**Request:** +```bash +curl -X POST "http://your-server.com/cSbuFLhp/?api_key=8D3135D30437F86EAE2FA4A2A8345000&action=enable_line" \ + -d "id=123" +``` + +--- + +## ⛔ Disable Line + +### Action: `disable_line` + +Temporarily suspend a line without deleting it. + +**Required Parameters:** +- `id` - Line ID to disable + +**Request:** +```bash +curl -X POST "http://your-server.com/cSbuFLhp/?api_key=8D3135D30437F86EAE2FA4A2A8345000&action=disable_line" \ + -d "id=123" +``` + +--- + +## 🚫 Ban Line + +### Action: `ban_line` + +Permanently block an abusive or fraudulent account. + +**Required Parameters:** +- `id` - Line ID to ban + +**Request:** +```bash +curl -X POST "http://your-server.com/cSbuFLhp/?api_key=8D3135D30437F86EAE2FA4A2A8345000&action=ban_line" \ + -d "id=123" +``` + +--- + +## ✓ Unban Line + +### Action: `unban_line` + +Remove ban from a previously banned line. + +**Required Parameters:** +- `id` - Line ID to unban + +**Request:** +```bash +curl -X POST "http://your-server.com/cSbuFLhp/?api_key=8D3135D30437F86EAE2FA4A2A8345000&action=unban_line" \ + -d "id=123" +``` + +--- + +## 💻 Code Examples + +### Python + +```python +import requests +from datetime import datetime, timedelta + +class XUILineManager: + def __init__(self, base_url, api_key): + self.base_url = base_url + self.api_key = api_key + + def _make_request(self, action, data=None): + """Make API request""" + params = { + "api_key": self.api_key, + "action": action + } + + if data: + response = requests.post(self.base_url, params=params, data=data) + else: + response = requests.get(self.base_url, params=params) + + result = response.json() + if result["status"] != "STATUS_SUCCESS": + raise Exception(f"API Error: {result.get('error', 'Unknown error')}") + + return result["data"] + + def get_line(self, line_id): + """Get specific line details""" + return self._make_request("get_line", {"id": line_id}) + + def create_line(self, username, password, **kwargs): + """Create new subscription line""" + data = { + "username": username, + "password": password, + **kwargs + } + return self._make_request("create_line", data) + + def edit_line(self, line_id, **kwargs): + """Edit existing line""" + data = {"id": line_id, **kwargs} + return self._make_request("edit_line", data) + + def delete_line(self, line_id): + """Delete line""" + return self._make_request("delete_line", {"id": line_id}) + + def enable_line(self, line_id): + """Enable line""" + return self._make_request("enable_line", {"id": line_id}) + + def disable_line(self, line_id): + """Disable line""" + return self._make_request("disable_line", {"id": line_id}) + + def ban_line(self, line_id): + """Ban line""" + return self._make_request("ban_line", {"id": line_id}) + + def unban_line(self, line_id): + """Unban line""" + return self._make_request("unban_line", {"id": line_id}) + +# Usage Example +manager = XUILineManager( + base_url="http://your-server.com/cSbuFLhp/", + api_key="8D3135D30437F86EAE2FA4A2A8345000" +) + +# Create new line +new_line = manager.create_line( + username="customer001", + password="secure123", + max_connections=1, + exp_date="2025-12-31", + bouquets_selected=[1, 2, 3], + notes="Premium customer" +) +print(f"Created line ID: {new_line['line_id']}") + +# Get line details +line = manager.get_line(123) +print(f"Line: {line['username']} - Expires: {line['exp_date']}") + +# Edit line +manager.edit_line( + line_id=123, + password="newpassword", + max_connections=2 +) +print("Line updated successfully") + +# Disable line +manager.disable_line(123) +print("Line disabled") +``` + +--- + +### PHP + +```php +baseUrl = $baseUrl; + $this->apiKey = $apiKey; + } + + private function makeRequest($action, $data = null) { + $url = $this->baseUrl . "?api_key=" . $this->apiKey . "&action=" . $action; + + if ($data) { + $options = [ + 'http' => [ + 'method' => 'POST', + 'header' => 'Content-type: application/x-www-form-urlencoded', + 'content' => http_build_query($data) + ] + ]; + $context = stream_context_create($options); + $response = file_get_contents($url, false, $context); + } else { + $response = file_get_contents($url); + } + + $result = json_decode($response, true); + + if ($result['status'] !== 'STATUS_SUCCESS') { + throw new Exception("API Error: " . ($result['error'] ?? 'Unknown error')); + } + + return $result['data']; + } + + public function getLine($lineId) { + return $this->makeRequest("get_line", ["id" => $lineId]); + } + + public function createLine($username, $password, $options = []) { + $data = array_merge([ + "username" => $username, + "password" => $password + ], $options); + + return $this->makeRequest("create_line", $data); + } + + public function editLine($lineId, $updates) { + $data = array_merge(["id" => $lineId], $updates); + return $this->makeRequest("edit_line", $data); + } + + public function deleteLine($lineId) { + return $this->makeRequest("delete_line", ["id" => $lineId]); + } + + public function enableLine($lineId) { + return $this->makeRequest("enable_line", ["id" => $lineId]); + } + + public function disableLine($lineId) { + return $this->makeRequest("disable_line", ["id" => $lineId]); + } +} + +// Usage Example +$manager = new XUILineManager( + "http://your-server.com/cSbuFLhp/", + "8D3135D30437F86EAE2FA4A2A8345000" +); + +// Create new line +$newLine = $manager->createLine( + "customer001", + "secure123", + [ + "max_connections" => 1, + "exp_date" => "2025-12-31", + "notes" => "Premium customer" + ] +); +echo "Created line ID: " . $newLine['line_id'] . "\n"; + +// Edit line +$manager->editLine(123, [ + "password" => "newpassword", + "max_connections" => 2 +]); +echo "Line updated successfully\n"; +?> +``` + +--- + +### JavaScript (Node.js) + +```javascript +const fetch = require('node-fetch'); + +class XUILineManager { + constructor(baseUrl, apiKey) { + this.baseUrl = baseUrl; + this.apiKey = apiKey; + } + + async makeRequest(action, data = null) { + const url = `${this.baseUrl}?api_key=${this.apiKey}&action=${action}`; + + const options = { + method: data ? 'POST' : 'GET', + }; + + if (data) { + const formData = new URLSearchParams(); + for (const [key, value] of Object.entries(data)) { + if (Array.isArray(value)) { + value.forEach(v => formData.append(`${key}[]`, v)); + } else { + formData.append(key, value); + } + } + options.body = formData; + } + + const response = await fetch(url, options); + const result = await response.json(); + + if (result.status !== 'STATUS_SUCCESS') { + throw new Error(`API Error: ${result.error || 'Unknown error'}`); + } + + return result.data; + } + + async getLine(lineId) { + const url = `${this.baseUrl}?api_key=${this.apiKey}&action=get_line&id=${lineId}`; + const response = await fetch(url); + const result = await response.json(); + + if (result.status !== 'STATUS_SUCCESS') { + throw new Error(`API Error: ${result.error || 'Unknown error'}`); + } + + return result.data; + } + + async createLine(username, password, options = {}) { + const data = { username, password, ...options }; + return this.makeRequest('create_line', data); + } + + async editLine(lineId, updates) { + const data = { id: lineId, ...updates }; + return this.makeRequest('edit_line', data); + } + + async deleteLine(lineId) { + return this.makeRequest('delete_line', { id: lineId }); + } + + async enableLine(lineId) { + return this.makeRequest('enable_line', { id: lineId }); + } + + async disableLine(lineId) { + return this.makeRequest('disable_line', { id: lineId }); + } + + async banLine(lineId) { + return this.makeRequest('ban_line', { id: lineId }); + } + + async unbanLine(lineId) { + return this.makeRequest('unban_line', { id: lineId }); + } +} + +// Usage Example +(async () => { + const manager = new XUILineManager( + 'http://your-server.com/cSbuFLhp/', + '8D3135D30437F86EAE2FA4A2A8345000' + ); + + try { + // Create new line + const newLine = await manager.createLine( + 'customer001', + 'secure123', + { + max_connections: 1, + exp_date: '2025-12-31', + bouquets_selected: [1, 2, 3], + notes: 'Premium customer' + } + ); + console.log('Created line ID:', newLine.line_id); + + // Get line details + const line = await manager.getLine(123); + console.log('Line:', line.username, '- Expires:', line.exp_date); + + // Edit line + await manager.editLine(123, { + password: 'newpassword', + max_connections: 2 + }); + console.log('Line updated successfully'); + + } catch (error) { + console.error('Error:', error.message); + } +})(); +``` + +--- + +## 🎯 Common Use Cases + +### 1. Bulk Create Lines + +```python +def bulk_create_lines(manager, count=10, package_ids=[1,2,3]): + """Create multiple lines at once""" + import random + import string + + created_lines = [] + + for i in range(count): + # Generate random credentials + username = f"user{''.join(random.choices(string.digits, k=6))}" + password = ''.join(random.choices(string.ascii_letters + string.digits, k=12)) + + try: + result = manager.create_line( + username=username, + password=password, + max_connections=1, + exp_date="1month", # 1 month from now + bouquets_selected=package_ids + ) + + created_lines.append({ + 'id': result['line_id'], + 'username': username, + 'password': password + }) + + print(f"✓ Created: {username}") + + except Exception as e: + print(f"✗ Failed to create line {i+1}: {e}") + + return created_lines +``` + +### 2. Auto-Disable Expired Lines + +```python +from datetime import datetime + +def disable_expired_lines(manager): + """Automatically disable lines that have expired""" + # Get all lines + response = requests.get( + manager.base_url, + params={"api_key": manager.api_key, "action": "get_lines"} + ) + lines = response.json()['data'] + + now = datetime.now().timestamp() + expired_count = 0 + + for line in lines: + exp_date = int(line['exp_date']) + + # Check if expired and still enabled + if exp_date < now and line['enabled'] == '1': + try: + manager.disable_line(line['id']) + print(f"✓ Disabled expired line: {line['username']}") + expired_count += 1 + except Exception as e: + print(f"✗ Failed to disable {line['username']}: {e}") + + print(f"\nDisabled {expired_count} expired lines") +``` + +### 3. Reset Password for Line + +```python +import secrets +import string + +def reset_line_password(manager, line_id): + """Generate and set a new secure password""" + # Generate secure password + alphabet = string.ascii_letters + string.digits + new_password = ''.join(secrets.choice(alphabet) for i in range(16)) + + # Update line + manager.edit_line(line_id, password=new_password) + + return new_password + +# Usage +new_pass = reset_line_password(manager, 123) +print(f"New password: {new_pass}") +``` + +### 4. Extend Expiration Date + +```python +from datetime import datetime, timedelta + +def extend_subscription(manager, line_id, months=1): + """Extend line expiration by specified months""" + # Get current line + line = manager.get_line(line_id) + + # Calculate new expiration + current_exp = datetime.fromtimestamp(int(line['exp_date'])) + new_exp = current_exp + timedelta(days=30 * months) + new_exp_timestamp = int(new_exp.timestamp()) + + # Update line + manager.edit_line(line_id, exp_date=new_exp_timestamp) + + print(f"Extended to: {new_exp.strftime('%Y-%m-%d')}") +``` + +### 5. Upgrade Line to Different Package + +```python +def upgrade_line_package(manager, line_id, new_package_ids): + """Change line's assigned packages""" + manager.edit_line( + line_id, + bouquets_selected=new_package_ids + ) + + print(f"Upgraded line {line_id} to packages: {new_package_ids}") + +# Usage +upgrade_line_package(manager, 123, [1, 2, 3, 4, 5]) # Premium package +``` + +### 6. Export Line Credentials + +```python +import csv + +def export_lines_to_csv(manager, filename="lines_export.csv"): + """Export all lines to CSV file""" + # Get all lines + response = requests.get( + manager.base_url, + params={"api_key": manager.api_key, "action": "get_lines"} + ) + lines = response.json()['data'] + + # Write to CSV + with open(filename, 'w', newline='') as csvfile: + fieldnames = ['id', 'username', 'password', 'exp_date', 'max_connections', 'enabled'] + writer = csv.DictWriter(csvfile, fieldnames=fieldnames) + + writer.writeheader() + for line in lines: + writer.writerow({ + 'id': line['id'], + 'username': line['username'], + 'password': line['password'], + 'exp_date': datetime.fromtimestamp(int(line['exp_date'])).strftime('%Y-%m-%d'), + 'max_connections': line['max_connections'], + 'enabled': 'Yes' if line['enabled'] == '1' else 'No' + }) + + print(f"Exported {len(lines)} lines to {filename}") +``` + +--- + +## 📊 Expiration Date Formats + +XUI.ONE accepts multiple formats for expiration dates: + +### 1. Specific Date (YYYY-MM-DD) +```bash +-d "exp_date=2025-12-31" +``` + +### 2. Unix Timestamp +```bash +-d "exp_date=1735689600" +``` + +### 3. Relative Time +```bash +# Hours +-d "exp_date=24hours" + +# Days +-d "exp_date=7days" + +# Months +-d "exp_date=1month" +-d "exp_date=3months" + +# Years +-d "exp_date=1year" +``` + +### Python Helper Function + +```python +from datetime import datetime, timedelta + +def format_exp_date(days=None, months=None, years=None, date=None): + """Convert various formats to Unix timestamp""" + if date: + # Specific date + dt = datetime.strptime(date, '%Y-%m-%d') + else: + # Relative date + dt = datetime.now() + if days: + dt += timedelta(days=days) + if months: + dt += timedelta(days=30 * months) + if years: + dt += timedelta(days=365 * years) + + return int(dt.timestamp()) + +# Usage +exp_date = format_exp_date(months=3) # 3 months from now +``` + +--- + +## ⚠️ Important Notes + +### Username/Password Requirements + +- **Username:** 3-50 characters, alphanumeric +- **Password:** Minimum 6 characters recommended +- **No special characters** in username (use only letters, numbers, underscore) + +### Bouquet Selection + +When assigning bouquets, use array notation: +```bash +# cURL +-d "bouquets_selected[]=1" \ +-d "bouquets_selected[]=2" + +# Python +bouquets_selected=[1, 2, 3] + +# PHP +["bouquets_selected" => [1, 2, 3]] +``` + +### Max Connections + +- **Minimum:** 1 +- **Maximum:** Unlimited (but reasonable limits recommended) +- **Common values:** 1-5 for home users, 10-50 for resellers + +### Trial vs. Regular Lines + +Trial lines can be automatically converted to regular lines: +```python +# Create trial +manager.create_line( + username="trial001", + password="temp123", + is_trial=1, + exp_date="7days" +) + +# Convert to regular (when customer pays) +manager.edit_line( + line_id=123, + is_trial=0, + exp_date="1year" +) +``` + +--- + +## 💡 Best Practices + +### 1. Always Check Before Delete + +```python +def safe_delete_line(manager, line_id): + """Delete line with confirmation""" + try: + # Get line details first + line = manager.get_line(line_id) + + # Confirm it's the right line + print(f"About to delete: {line['username']}") + confirm = input("Are you sure? (yes/no): ") + + if confirm.lower() == 'yes': + manager.delete_line(line_id) + print("Line deleted successfully") + else: + print("Deletion cancelled") + + except Exception as e: + print(f"Error: {e}") +``` + +### 2. Validate Input Data + +```python +def validate_line_data(username, password, max_connections): + """Validate line data before creation""" + errors = [] + + if len(username) < 3 or len(username) > 50: + errors.append("Username must be 3-50 characters") + + if not username.replace('_', '').isalnum(): + errors.append("Username must be alphanumeric") + + if len(password) < 6: + errors.append("Password must be at least 6 characters") + + if max_connections < 1: + errors.append("Max connections must be at least 1") + + return errors + +# Usage +errors = validate_line_data("user123", "pass", 1) +if errors: + print("Validation errors:") + for error in errors: + print(f" - {error}") +else: + # Create line + manager.create_line("user123", "secure123", max_connections=1) +``` + +### 3. Implement Rate Limiting + +```python +import time +from functools import wraps + +def rate_limit(calls_per_second=2): + """Limit API calls to prevent overload""" + min_interval = 1.0 / calls_per_second + last_called = [0.0] + + def decorator(func): + @wraps(func) + def wrapper(*args, **kwargs): + elapsed = time.time() - last_called[0] + left_to_wait = min_interval - elapsed + + if left_to_wait > 0: + time.sleep(left_to_wait) + + result = func(*args, **kwargs) + last_called[0] = time.time() + return result + return wrapper + return decorator + +# Apply to methods +XUILineManager.create_line = rate_limit()(XUILineManager.create_line) +``` + +### 4. Error Handling + +```python +def create_line_with_retry(manager, username, password, retries=3): + """Create line with automatic retry on failure""" + for attempt in range(retries): + try: + return manager.create_line(username, password) + except Exception as e: + if attempt < retries - 1: + print(f"Attempt {attempt + 1} failed: {e}. Retrying...") + time.sleep(2 ** attempt) # Exponential backoff + else: + print(f"All {retries} attempts failed") + raise +``` + +--- + +## 📚 Related Documentation + +- [GET INFO API - Query Lines](02-get-info.md#1-get-all-subscription-lines) +- [Authentication Guide](../authentication.md) +- [Error Handling](../error-codes.md) + +--- + +## 🆘 Need Help? + +- **GitHub Issues:** [Report problems](https://github.com/worldofiptvcom/xui-one-api-docs/issues) +- **Community:** [World of IPTV Forums](https://www.worldofiptv.com) +- **Documentation:** [Getting Started Guide](../getting-started.md) diff --git a/openapi.yaml b/openapi.yaml index cdcc2fe..02a2bec 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -758,6 +758,551 @@ paths: '401': $ref: '#/components/responses/Unauthorized' + /?action=get_line: + get: + summary: Get Specific Line Details + description: | + Retrieves detailed information about a specific subscription line by ID. + + **Purpose:** View detailed information for a single line. + + --- + + **Example Request:** + ```bash + curl "http://your-server.com/cSbuFLhp/?api_key=8D3135D30437F86EAE2FA4A2A8345000&action=get_line&id=123" + ``` + + **Use Cases:** + - ✅ View specific line details + - ✅ Check line status before editing + - ✅ Verify line configuration + - ✅ Audit line settings + operationId: getLine + tags: + - Line API + parameters: + - $ref: '#/components/parameters/ApiKey' + - name: action + in: query + required: true + schema: + type: string + enum: [get_line] + - name: id + in: query + required: true + description: Line ID + schema: + type: integer + example: 123 + responses: + '200': + description: Line details retrieved successfully + content: + application/json: + schema: + allOf: + - $ref: '#/components/schemas/SuccessResponse' + - type: object + properties: + data: + $ref: '#/components/schemas/Line' + '401': + $ref: '#/components/responses/Unauthorized' + '404': + $ref: '#/components/responses/NotFound' + + /?action=create_line: + post: + summary: Create New Subscription Line + description: | + Creates a new subscription line (M3U/Xtream Codes account). + + **Purpose:** Add new subscriptions to your panel. + + --- + + **Example Request:** + ```bash + curl -X POST "http://your-server.com/cSbuFLhp/?api_key=8D3135D30437F86EAE2FA4A2A8345000&action=create_line" \ + -d "username=newuser" \ + -d "password=newpass123" \ + -d "max_connections=1" \ + -d "exp_date=2025-12-31" \ + -d "bouquets_selected[]=1" \ + -d "bouquets_selected[]=2" + ``` + + **Response Example:** + ```json + { + "status": "STATUS_SUCCESS", + "data": { + "line_id": "456", + "username": "newuser", + "password": "newpass123" + } + } + ``` + + **Use Cases:** + - ✅ Create new subscriptions + - ✅ Add trial accounts + - ✅ Set up reseller lines + - ✅ Bulk create accounts + operationId: createLine + tags: + - Line API + parameters: + - $ref: '#/components/parameters/ApiKey' + - name: action + in: query + required: true + schema: + type: string + enum: [create_line] + requestBody: + required: true + content: + application/x-www-form-urlencoded: + schema: + type: object + required: + - username + - password + properties: + username: + type: string + description: Username for the line + example: "newuser" + password: + type: string + description: Password for the line + example: "newpass123" + max_connections: + type: integer + description: Maximum concurrent connections + default: 1 + example: 1 + exp_date: + type: string + description: Expiration date (YYYY-MM-DD, Unix timestamp, or relative like "1month", "1year") + example: "2025-12-31" + is_trial: + type: integer + description: Trial account (0 = No, 1 = Yes) + enum: [0, 1] + default: 0 + example: 0 + is_restreamer: + type: integer + description: Reseller status (0 = No, 1 = Yes) + enum: [0, 1] + default: 0 + example: 0 + bouquets_selected: + type: array + description: Array of bouquet/package IDs to assign + items: + type: integer + example: [1, 2, 3] + notes: + type: string + description: Admin notes + example: "Premium customer" + contact: + type: string + description: Contact information + example: "customer@example.com" + isp_lock: + type: string + description: Lock to specific IP address + example: "192.168.1.100" + responses: + '200': + description: Line created successfully + content: + application/json: + schema: + allOf: + - $ref: '#/components/schemas/SuccessResponse' + '401': + $ref: '#/components/responses/Unauthorized' + + /?action=edit_line: + post: + summary: Edit Existing Line + description: | + Modifies an existing subscription line. + + **Purpose:** Update line settings and configuration. + + --- + + **Example Request:** + ```bash + curl -X POST "http://your-server.com/cSbuFLhp/?api_key=8D3135D30437F86EAE2FA4A2A8345000&action=edit_line" \ + -d "id=123" \ + -d "password=newpassword" \ + -d "max_connections=2" + ``` + + **Use Cases:** + - ✅ Change passwords + - ✅ Update connection limits + - ✅ Modify expiration dates + - ✅ Change assigned packages + - ✅ Update notes + operationId: editLine + tags: + - Line API + parameters: + - $ref: '#/components/parameters/ApiKey' + - name: action + in: query + required: true + schema: + type: string + enum: [edit_line] + requestBody: + required: true + content: + application/x-www-form-urlencoded: + schema: + type: object + required: + - id + properties: + id: + type: integer + description: Line ID to edit + example: 123 + username: + type: string + description: New username + example: "updateduser" + password: + type: string + description: New password + example: "newpass456" + max_connections: + type: integer + description: Maximum concurrent connections + example: 2 + exp_date: + type: string + description: New expiration date + example: "2026-12-31" + is_trial: + type: integer + description: Trial status + enum: [0, 1] + example: 0 + bouquets_selected: + type: array + description: Updated bouquet IDs + items: + type: integer + example: [1, 2, 3, 4] + notes: + type: string + description: Updated notes + example: "Extended subscription" + responses: + '200': + description: Line updated successfully + content: + application/json: + schema: + $ref: '#/components/schemas/SuccessResponse' + '401': + $ref: '#/components/responses/Unauthorized' + '404': + $ref: '#/components/responses/NotFound' + + /?action=delete_line: + post: + summary: Delete Line + description: | + Permanently deletes a subscription line. + + **Purpose:** Remove lines from the panel. + + ⚠️ **Warning:** This action cannot be undone! + + --- + + **Example Request:** + ```bash + curl -X POST "http://your-server.com/cSbuFLhp/?api_key=8D3135D30437F86EAE2FA4A2A8345000&action=delete_line" \ + -d "id=123" + ``` + + **Use Cases:** + - ✅ Remove expired subscriptions + - ✅ Delete test accounts + - ✅ Clean up old lines + operationId: deleteLine + tags: + - Line API + parameters: + - $ref: '#/components/parameters/ApiKey' + - name: action + in: query + required: true + schema: + type: string + enum: [delete_line] + requestBody: + required: true + content: + application/x-www-form-urlencoded: + schema: + type: object + required: + - id + properties: + id: + type: integer + description: Line ID to delete + example: 123 + responses: + '200': + description: Line deleted successfully + content: + application/json: + schema: + $ref: '#/components/schemas/SuccessResponse' + '401': + $ref: '#/components/responses/Unauthorized' + '404': + $ref: '#/components/responses/NotFound' + + /?action=enable_line: + post: + summary: Enable Line + description: | + Enables a disabled subscription line. + + **Purpose:** Reactivate suspended lines. + + --- + + **Example Request:** + ```bash + curl -X POST "http://your-server.com/cSbuFLhp/?api_key=8D3135D30437F86EAE2FA4A2A8345000&action=enable_line" \ + -d "id=123" + ``` + + **Use Cases:** + - ✅ Reactivate suspended accounts + - ✅ Resume service after payment + - ✅ Restore access + operationId: enableLine + tags: + - Line API + parameters: + - $ref: '#/components/parameters/ApiKey' + - name: action + in: query + required: true + schema: + type: string + enum: [enable_line] + requestBody: + required: true + content: + application/x-www-form-urlencoded: + schema: + type: object + required: + - id + properties: + id: + type: integer + description: Line ID to enable + example: 123 + responses: + '200': + description: Line enabled successfully + content: + application/json: + schema: + $ref: '#/components/schemas/SuccessResponse' + '401': + $ref: '#/components/responses/Unauthorized' + '404': + $ref: '#/components/responses/NotFound' + + /?action=disable_line: + post: + summary: Disable Line + description: | + Disables an active subscription line without deleting it. + + **Purpose:** Temporarily suspend access. + + --- + + **Example Request:** + ```bash + curl -X POST "http://your-server.com/cSbuFLhp/?api_key=8D3135D30437F86EAE2FA4A2A8345000&action=disable_line" \ + -d "id=123" + ``` + + **Use Cases:** + - ✅ Suspend non-payment accounts + - ✅ Temporarily block access + - ✅ Pause service + operationId: disableLine + tags: + - Line API + parameters: + - $ref: '#/components/parameters/ApiKey' + - name: action + in: query + required: true + schema: + type: string + enum: [disable_line] + requestBody: + required: true + content: + application/x-www-form-urlencoded: + schema: + type: object + required: + - id + properties: + id: + type: integer + description: Line ID to disable + example: 123 + responses: + '200': + description: Line disabled successfully + content: + application/json: + schema: + $ref: '#/components/schemas/SuccessResponse' + '401': + $ref: '#/components/responses/Unauthorized' + '404': + $ref: '#/components/responses/NotFound' + + /?action=ban_line: + post: + summary: Ban Line + description: | + Bans a subscription line, blocking access and preventing reactivation. + + **Purpose:** Permanently block abusive or fraudulent accounts. + + --- + + **Example Request:** + ```bash + curl -X POST "http://your-server.com/cSbuFLhp/?api_key=8D3135D30437F86EAE2FA4A2A8345000&action=ban_line" \ + -d "id=123" + ``` + + **Use Cases:** + - ✅ Block fraudulent accounts + - ✅ Prevent abuse + - ✅ Enforce terms of service + operationId: banLine + tags: + - Line API + parameters: + - $ref: '#/components/parameters/ApiKey' + - name: action + in: query + required: true + schema: + type: string + enum: [ban_line] + requestBody: + required: true + content: + application/x-www-form-urlencoded: + schema: + type: object + required: + - id + properties: + id: + type: integer + description: Line ID to ban + example: 123 + responses: + '200': + description: Line banned successfully + content: + application/json: + schema: + $ref: '#/components/schemas/SuccessResponse' + '401': + $ref: '#/components/responses/Unauthorized' + '404': + $ref: '#/components/responses/NotFound' + + /?action=unban_line: + post: + summary: Unban Line + description: | + Removes ban from a previously banned line. + + **Purpose:** Restore access to banned accounts. + + --- + + **Example Request:** + ```bash + curl -X POST "http://your-server.com/cSbuFLhp/?api_key=8D3135D30437F86EAE2FA4A2A8345000&action=unban_line" \ + -d "id=123" + ``` + + **Use Cases:** + - ✅ Unban false positives + - ✅ Restore access after appeal + - ✅ Second chances + operationId: unbanLine + tags: + - Line API + parameters: + - $ref: '#/components/parameters/ApiKey' + - name: action + in: query + required: true + schema: + type: string + enum: [unban_line] + requestBody: + required: true + content: + application/x-www-form-urlencoded: + schema: + type: object + required: + - id + properties: + id: + type: integer + description: Line ID to unban + example: 123 + responses: + '200': + description: Line unbanned successfully + content: + application/json: + schema: + $ref: '#/components/schemas/SuccessResponse' + '401': + $ref: '#/components/responses/Unauthorized' + '404': + $ref: '#/components/responses/NotFound' + components: securitySchemes: ApiKeyAuth: