{"openapi":"3.0.0","paths":{"/login/signup":{"post":{"operationId":"signUp","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateUserDto"}}}},"responses":{"201":{"description":"User successfully registered","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthResponseDto"}}}},"400":{"description":"Invalid input data"},"409":{"description":"User already exists"},"429":{"description":"Too many requests - rate limit exceeded"}},"summary":"Register a new user","tags":["Authentication"]}},"/login/signin":{"post":{"operationId":"signIn","parameters":[{"name":"user-agent","required":true,"in":"header","schema":{"type":"string"}},{"name":"x-forwarded-for","required":true,"in":"header","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoginUserDto"}}}},"responses":{"200":{"description":"User successfully signed in","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthResponseDto"}}}},"400":{"description":"Invalid input data"},"401":{"description":"Invalid credentials"},"429":{"description":"Too many requests - rate limit exceeded"}},"summary":"Sign in user","tags":["Authentication"]}},"/login/verify-email":{"get":{"operationId":"verifyEmail","parameters":[{"name":"token","required":true,"in":"query","description":"Email verification token","schema":{"type":"string"}}],"responses":{"200":{"description":"Email verified successfully with auth token for auto-login"},"400":{"description":"Invalid or expired token"}},"summary":"Verify user email address and return auth token for auto-login","tags":["Authentication"]}},"/login/resend-verification":{"post":{"operationId":"resendVerificationEmail","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"properties":{"email":{"type":"string","format":"email"}}}}}},"responses":{"200":{"description":"Verification email sent if account exists"},"429":{"description":"Too many requests - rate limit exceeded"}},"summary":"Resend verification email","tags":["Authentication"]}},"/login/forgot-password":{"post":{"operationId":"forgotPassword","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"properties":{"email":{"type":"string","format":"email"}}}}}},"responses":{"200":{"description":"Password reset email sent if account exists"},"429":{"description":"Too many requests - rate limit exceeded"}},"summary":"Request password reset email","tags":["Authentication"]}},"/login/reset-password":{"post":{"operationId":"resetPassword","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"properties":{"token":{"type":"string","description":"Password reset token from email"},"password":{"type":"string","description":"New password (min 8 characters)"}},"required":["token","password"]}}}},"responses":{"200":{"description":"Password reset successful"},"400":{"description":"Invalid or expired token"},"429":{"description":"Too many requests - rate limit exceeded"}},"summary":"Reset password using token","tags":["Authentication"]}},"/login/promote-to-farmer":{"post":{"description":"Used when a customer wants to become a farmer. Only works for customer accounts. Returns new JWT with farmer role.","operationId":"promoteToFarmer","parameters":[],"responses":{"200":{"description":"User promoted to farmer successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthResponseDto"}}}},"401":{"description":"Unauthorized"},"429":{"description":"Too many requests - rate limit exceeded"}},"security":[{"JWT-auth":[]}],"summary":"Promote customer account to farmer role","tags":["Authentication"]}},"/api-keys":{"post":{"description":"Generate a new API key for programmatic access. The plain API key is only shown once - save it securely!","operationId":"createApiKey","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string","description":"Friendly name for the API key","example":"My MCP Server"},"scopes":{"type":"array","items":{"type":"string"},"description":"Permission scopes for the key","example":["ports:read","ports:write","billing:read"]},"expiresInDays":{"type":"number","description":"Days until the key expires (0 = never)","example":90},"rateLimit":{"type":"number","description":"Requests per minute (default: 100)","example":100}}}}}},"responses":{"201":{"description":"API key created successfully","content":{"application/json":{"schema":{"type":"object","properties":{"apiKey":{"type":"string","description":"The plain API key (only shown once!)","example":"psx_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6"},"keyInfo":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"keyPrefix":{"type":"string","example":"psx_a1b2c3d4"},"scopes":{"type":"array","items":{"type":"string"}},"isActive":{"type":"boolean"},"expiresAt":{"type":"string","format":"date-time"},"rateLimit":{"type":"number"},"createdAt":{"type":"string","format":"date-time"}}}}}}}},"400":{"description":"Invalid input or max keys reached"}},"security":[{"bearer":[]}],"summary":"Create a new API key","tags":["API Keys"]},"get":{"description":"Get all API keys for the current user. Keys are masked for security.","operationId":"listApiKeys","parameters":[],"responses":{"200":{"description":"List of API keys","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"keyPrefix":{"type":"string","example":"psx_a1b2c3d4"},"scopes":{"type":"array","items":{"type":"string"}},"isActive":{"type":"boolean"},"lastUsedAt":{"type":"string","format":"date-time"},"expiresAt":{"type":"string","format":"date-time"},"usageCount":{"type":"number"},"rateLimit":{"type":"number"},"createdAt":{"type":"string","format":"date-time"}}}}}}}},"security":[{"bearer":[]}],"summary":"List all API keys","tags":["API Keys"]}},"/api-keys/scopes":{"get":{"description":"List all available permission scopes and whether they are available for your role.","operationId":"getAvailableScopes","parameters":[],"responses":{"200":{"description":"List of available scopes","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"scope":{"type":"string","example":"ports:read"},"description":{"type":"string","example":"Read port information"},"available":{"type":"boolean"}}}}}}}},"security":[{"bearer":[]}],"summary":"Get available API key scopes","tags":["API Keys"]}},"/api-keys/{keyId}":{"get":{"operationId":"getApiKey","parameters":[{"name":"keyId","required":true,"in":"path","description":"API key ID","schema":{"type":"string"}}],"responses":{"200":{"description":"API key details"},"404":{"description":"API key not found"}},"security":[{"bearer":[]}],"summary":"Get API key details","tags":["API Keys"]},"put":{"description":"Update name, scopes, or rate limit of an API key.","operationId":"updateApiKey","parameters":[{"name":"keyId","required":true,"in":"path","description":"API key ID","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","example":"Updated name"},"scopes":{"type":"array","items":{"type":"string"},"example":["ports:read","billing:read"]},"rateLimit":{"type":"number","example":200}}}}}},"responses":{"200":{"description":"API key updated"},"404":{"description":"API key not found"}},"security":[{"bearer":[]}],"summary":"Update API key","tags":["API Keys"]},"delete":{"description":"Permanently delete an API key.","operationId":"deleteApiKey","parameters":[{"name":"keyId","required":true,"in":"path","description":"API key ID","schema":{"type":"string"}}],"responses":{"200":{"description":"API key deleted"},"404":{"description":"API key not found"}},"security":[{"bearer":[]}],"summary":"Delete API key","tags":["API Keys"]}},"/api-keys/{keyId}/regenerate":{"post":{"description":"Generate a new key while keeping the same settings. The old key is immediately invalidated.","operationId":"regenerateApiKey","parameters":[{"name":"keyId","required":true,"in":"path","description":"API key ID","schema":{"type":"string"}}],"responses":{"200":{"description":"New API key generated","content":{"application/json":{"schema":{"type":"object","properties":{"apiKey":{"type":"string","description":"The new plain API key (only shown once!)"},"keyInfo":{"type":"object"}}}}}},"404":{"description":"API key not found"}},"security":[{"bearer":[]}],"summary":"Regenerate API key","tags":["API Keys"]}},"/api-keys/{keyId}/revoke":{"post":{"description":"Deactivate an API key without deleting it. Can be useful for audit purposes.","operationId":"revokeApiKey","parameters":[{"name":"keyId","required":true,"in":"path","description":"API key ID","schema":{"type":"string"}}],"responses":{"200":{"description":"API key revoked"},"404":{"description":"API key not found"}},"security":[{"bearer":[]}],"summary":"Revoke API key","tags":["API Keys"]}},"/account/summary":{"get":{"description":"Returns a compact summary of balance, slots, traffic, and alerts. Optimized for dashboard widgets and quick status checks. Admins can view other users by passing userId query param.","operationId":"getAccountSummary","parameters":[{"name":"userId","required":false,"in":"query","description":"Optional user ID (admin only) to view another user's summary","schema":{"type":"string"}}],"responses":{"200":{"description":"Account summary retrieved successfully","content":{"application/json":{"example":{"balance":150,"currency":"USD","shared":{"slots":{"total":10,"used":8,"available":2},"trafficGB":{"total":100,"used":35,"available":65},"expiresAt":"2025-01-15T00:00:00Z","daysRemaining":28},"private":{"slots":{"total":5,"used":3,"available":2},"trafficGB":{"total":50,"used":10,"available":40},"expiresAt":"2025-01-20T00:00:00Z","daysRemaining":33},"alerts":[{"type":"low_traffic","message":"Traffic is running low (< 5GB)","severity":"info"}]}}}},"401":{"description":"Unauthorized - Invalid token"}},"security":[{"JWT-auth":[]}],"summary":"Get lightweight account summary for dashboard widgets","tags":["Account"]}},"/account/usage":{"get":{"description":"Returns detailed traffic usage breakdown by port and slot type. Useful for monitoring and analytics.","operationId":"getAccountUsage","parameters":[{"name":"period","required":false,"in":"query","description":"Time period for usage data (default: 30d)","schema":{"enum":["7d","30d","90d"],"type":"string"}}],"responses":{"200":{"description":"Usage analytics retrieved successfully","content":{"application/json":{"example":{"period":"30d","generatedAt":"2024-12-17T10:30:00Z","traffic":{"shared":{"totalUsedGB":35.5,"portCount":8,"byPort":[{"portId":"...","portName":"psx_abc123","usedGB":15.2,"slotType":"shared"},{"portId":"...","portName":"psx_def456","usedGB":12.1,"slotType":"shared"}]},"private":{"totalUsedGB":10,"portCount":3,"byPort":[{"portId":"...","portName":"psx_xyz789","usedGB":5.5,"slotType":"private"}]},"combined":{"totalUsedGB":45.5,"portCount":11}}}}}},"401":{"description":"Unauthorized - Invalid token"}},"security":[{"JWT-auth":[]}],"summary":"Get traffic and usage analytics","tags":["Account"]}},"/account/complete-profile":{"post":{"description":"Allows users to complete their profile with additional information like Telegram, use case, target domains, and budget. This data helps with personalized support and sales follow-up.","operationId":"completeProfile","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"Full name","example":"John Doe"},"phone":{"type":"string","description":"Phone number","example":"+1234567890"},"telegram":{"type":"string","description":"Telegram username","example":"@johndoe"},"targetDomains":{"type":"array","items":{"type":"string"},"description":"Target websites/domains","example":["facebook.com","google.com"]},"useCase":{"type":"string","enum":["scraping","account_management","ad_verification","social_media","ecommerce","seo","other"],"description":"Primary use case"},"monthlyBudget":{"type":"string","enum":["$0-50","$50-200","$200-500","$500+"],"description":"Expected monthly budget"},"expectedTraffic":{"type":"string","enum":["1-10GB","10-50GB","50-100GB","100GB+"],"description":"Expected monthly traffic"},"organization":{"type":"string","description":"Organization/company name","example":"Tech Corp"},"country":{"type":"string","description":"Country","example":"United States"}}}}}},"responses":{"200":{"description":"Profile completed successfully","content":{"application/json":{"example":{"_id":"507f1f77bcf86cd799439011","email":"user@example.com","name":"John Doe","telegram":"@johndoe","useCase":"scraping","monthlyBudget":"$50-200","profileCompleted":true}}}},"401":{"description":"Unauthorized - Invalid token"}},"security":[{"JWT-auth":[]}],"summary":"Complete user profile with lead qualification data","tags":["Account"]}},"/account/proxy-password":{"get":{"description":"Returns the current proxy password in plaintext. The password is stored server-side and can always be retrieved.","operationId":"getProxyPassword","parameters":[],"responses":{"200":{"description":"Current proxy password","content":{"application/json":{"schema":{"type":"object","properties":{"proxyPassword":{"type":"string","nullable":true,"example":"ABCdef123456"},"proxyUsername":{"type":"string","nullable":true,"example":"psx_abc123"}}}}}}},"security":[{"JWT-auth":[]}],"summary":"Get current proxy password","tags":["Account"]},"patch":{"description":"Set or update the password used for proxy authentication (separate from account login password). Minimum 6 characters required.","operationId":"updateProxyPassword","parameters":[],"requestBody":{"required":true,"description":"New proxy password","content":{"application/json":{"schema":{"type":"object","required":["proxyPassword"],"properties":{"proxyPassword":{"type":"string","minLength":6,"description":"New password for proxy authentication","example":"mySecureProxyPass123"}}}}}},"responses":{"200":{"description":"Proxy password updated successfully","content":{"application/json":{"example":{"message":"Proxy password updated successfully","proxyUsername":"psx_507f1f77bcf86cd799439011"}}}},"400":{"description":"Invalid password (must be at least 6 characters)"},"401":{"description":"Unauthorized - Invalid token"}},"security":[{"JWT-auth":[]}],"summary":"Update proxy password","tags":["Account"]}},"/account/profile":{"patch":{"operationId":"updateProfile","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1}}}}}},"responses":{"200":{"description":"Profile updated"}},"security":[{"JWT-auth":[]}],"summary":"Update profile name","tags":["Account"]}},"/account":{"get":{"operationId":"getAccount","parameters":[{"name":"userId","required":false,"in":"query","description":"User ID (Admin only - to view other user accounts)","schema":{"type":"string"}}],"responses":{"200":{"description":"Account information retrieved successfully","content":{"application/json":{"example":{"user":{"_id":"507f1f77bcf86cd799439011","email":"user@example.com","role":"customer","isActive":true,"name":"John Doe","organization":"Example Corp","purpose":"Business","phone":"+1234567890","website":"https://example.com","country":"USA","company":"Example Inc","twoFAEnabled":false,"createdAt":"2024-01-01T00:00:00.000Z","updatedAt":"2024-01-01T00:00:00.000Z"},"wallets":[{"coin":"BTC","address":"1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa","testnetAddress":null,"livenetAddress":"1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa"},{"coin":"USDT","address":"0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb","testnetAddress":null,"livenetAddress":"0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb"}],"payments":[{"_id":"507f1f77bcf86cd799439022","coin":"btc","amount":0.001,"amountInUSD":65.5,"status":"confirmed","network":"mainnet","address":"1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa","txId":"6c44dc339b5a66a8e8d5b8d65d3b6e5f1d8e7a9b2c3d4e5f6a7b8c9d0e1f2a3b","confirmations":6,"sessionId":null,"paymentIntentId":null,"metadata":{},"createdAt":1697192400000,"updatedAt":1697192400000}],"ports":[{"_id":"507f1f77bcf86cd799439033","name":"port_abc12345","deviceId":"507f1f77bcf86cd799439044","httpPort":12345,"socksPort":12346,"serverIp":"192.168.1.100","proxyLogin":"user_abc123","proxyPassword":"pass123ABC!","exclusive":false,"createdAt":"2024-01-01T00:00:00.000Z","updatedAt":"2024-01-01T00:00:00.000Z"}],"topUp":65.5,"spent":0,"resources":{"ports":10,"traffic":1000}}}}},"401":{"description":"Unauthorized - Invalid token"},"404":{"description":"User not found"}},"security":[{"JWT-auth":[]}],"summary":"Get account information with linked wallets, payments, ports, payments","tags":["Account"]}},"/account/processes":{"get":{"operationId":"getProcesses","parameters":[],"responses":{"200":{"description":"User processes retrieved successfully","content":{"application/json":{"example":{"processes":[{"_id":"507f1f77bcf86cd799439011","type":"port_creation","status":"running","message":"Creating 5 ports in Germany","progress":60,"total":5,"completed":3,"failed":0,"metadata":{"countryName":"Germany"},"startedAt":"2024-01-01T00:00:00.000Z"}]}}}},"401":{"description":"Unauthorized - Invalid token"}},"security":[{"JWT-auth":[]}],"summary":"Get active and recent processes for the current user","tags":["Account"]}},"/account/processes/{processId}":{"get":{"operationId":"getProcess","parameters":[{"name":"processId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"Process retrieved successfully"},"401":{"description":"Unauthorized - Invalid token"},"404":{"description":"Process not found"}},"security":[{"JWT-auth":[]}],"summary":"Get a specific process by ID","tags":["Account"]}},"/account/processes/{processId}/cancel":{"post":{"operationId":"cancelProcess","parameters":[{"name":"processId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"Process cancelled successfully"},"401":{"description":"Unauthorized - Invalid token"},"404":{"description":"Process not found or cannot be cancelled"}},"security":[{"JWT-auth":[]}],"summary":"Cancel a running process","tags":["Account"]}},"/account/notifications":{"get":{"operationId":"getNotifications","parameters":[{"name":"unreadOnly","required":false,"in":"query","description":"Only return unread notifications","schema":{"type":"boolean"}},{"name":"limit","required":false,"in":"query","description":"Limit number of results (default 50)","schema":{"type":"number"}},{"name":"offset","required":false,"in":"query","description":"Offset for pagination","schema":{"type":"number"}}],"responses":{"200":{"description":"Notifications retrieved successfully","content":{"application/json":{"example":{"notifications":[{"_id":"507f1f77bcf86cd799439011","type":"warning","category":"port","title":"Port Expiring Soon","message":"Your port \"psx_abc123\" will expire in 24 hours.","isRead":false,"actionLink":"/my-proxies","actionLabel":"View Ports","createdAt":"2024-01-01T00:00:00.000Z"}],"total":10,"unreadCount":3}}}}},"security":[{"JWT-auth":[]}],"summary":"Get notifications for the current user","tags":["Account"]},"delete":{"operationId":"deleteAllNotifications","parameters":[],"responses":{"200":{"description":"All notifications deleted successfully"}},"security":[{"JWT-auth":[]}],"summary":"Delete all notifications","tags":["Account"]}},"/account/notifications/unread-count":{"get":{"operationId":"getUnreadCount","parameters":[],"responses":{"200":{"description":"Unread count retrieved successfully","content":{"application/json":{"example":{"unreadCount":5}}}}},"security":[{"JWT-auth":[]}],"summary":"Get unread notification count","tags":["Account"]}},"/account/notifications/{notificationId}/read":{"patch":{"operationId":"markNotificationAsRead","parameters":[{"name":"notificationId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"Notification marked as read"},"404":{"description":"Notification not found"}},"security":[{"JWT-auth":[]}],"summary":"Mark a notification as read","tags":["Account"]}},"/account/notifications/mark-all-read":{"post":{"operationId":"markAllNotificationsAsRead","parameters":[],"responses":{"200":{"description":"All notifications marked as read","content":{"application/json":{"example":{"modifiedCount":5}}}}},"security":[{"JWT-auth":[]}],"summary":"Mark all notifications as read","tags":["Account"]}},"/account/notifications/{notificationId}":{"delete":{"operationId":"deleteNotification","parameters":[{"name":"notificationId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"Notification deleted successfully"},"404":{"description":"Notification not found"}},"security":[{"JWT-auth":[]}],"summary":"Delete a notification","tags":["Account"]}},"/account/activities":{"get":{"operationId":"getActivities","parameters":[{"name":"type","required":false,"in":"query","description":"Filter by activity type","schema":{"type":"string"}},{"name":"limit","required":false,"in":"query","description":"Limit number of results (default 50)","schema":{"type":"number"}},{"name":"offset","required":false,"in":"query","description":"Offset for pagination","schema":{"type":"number"}}],"responses":{"200":{"description":"Activities retrieved successfully","content":{"application/json":{"example":{"activities":[{"_id":"507f1f77bcf86cd799439011","type":"port_created","description":"Port \"psx_abc123\" was created","entityId":"507f1f77bcf86cd799439022","entityType":"Port","metadata":{"portName":"psx_abc123","country":"Germany"},"createdAt":"2024-01-01T00:00:00.000Z"}],"total":25}}}}},"security":[{"JWT-auth":[]}],"summary":"Get activity history for the current user","tags":["Account"]}},"/account/email-preferences":{"get":{"operationId":"getEmailPreferences","parameters":[],"responses":{"200":{"description":"Email preferences retrieved successfully"}},"security":[{"JWT-auth":[]}],"summary":"Get user email preferences","tags":["Account"]},"patch":{"operationId":"updateEmailPreferences","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"marketing":{"type":"boolean"},"bandwidth":{"type":"boolean"},"portExpiring":{"type":"boolean"},"portRotation":{"type":"boolean"}}}}}},"responses":{"200":{"description":"Email preferences updated successfully"}},"security":[{"JWT-auth":[]}],"summary":"Update email preferences","tags":["Account"]}},"/account/email-preferences/unsubscribe-all":{"post":{"operationId":"unsubscribeFromAll","parameters":[],"responses":{"200":{"description":"Unsubscribed from all emails successfully"}},"security":[{"JWT-auth":[]}],"summary":"Unsubscribe from all marketing emails","tags":["Account"]}},"/account/email-preferences/resubscribe":{"post":{"operationId":"resubscribe","parameters":[],"responses":{"200":{"description":"Resubscribed successfully"}},"security":[{"JWT-auth":[]}],"summary":"Resubscribe to emails","tags":["Account"]}},"/account/security/sessions":{"get":{"description":"Returns a list of all active gateway authentication sessions for the current user. Sessions are identified by unique IP addresses and include geolocation data. Admins can pass userId query param to view other users.","operationId":"getActiveSessions","parameters":[{"name":"userId","required":false,"in":"query","description":"User ID (admin only) to view another user's sessions","schema":{"type":"string"}}],"responses":{"200":{"description":"Active sessions retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionListResponseDto"},"example":{"sessions":[{"sessionId":"507f1f77bcf86cd799439011","accountId":"psx_abc123","ip":"203.0.113.42","country":"US","countryName":"United States","city":"New York","userAgent":"Mozilla/5.0...","firstSeenAt":"2025-01-15T10:00:00Z","lastSeenAt":"2025-01-15T15:30:00Z","authCount":15,"isCurrent":true},{"sessionId":"507f1f77bcf86cd799439022","accountId":"psx_abc123","ip":"198.51.100.78","country":"GB","countryName":"United Kingdom","city":"London","userAgent":"curl/7.68.0","firstSeenAt":"2025-01-14T08:00:00Z","lastSeenAt":"2025-01-15T12:00:00Z","authCount":42,"isCurrent":false}],"total":2}}}},"401":{"description":"Unauthorized - Invalid token"}},"security":[{"JWT-auth":[]}],"summary":"Get all active sessions","tags":["Account"]},"delete":{"description":"Terminates all active sessions except the current one. This forces other devices/IPs to re-authenticate.","operationId":"killAllSessions","parameters":[],"responses":{"200":{"description":"All sessions killed successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KillSessionsResponseDto"},"example":{"killedCount":5,"message":"Killed 5 sessions (kept current session)"}}}},"401":{"description":"Unauthorized - Invalid token"}},"security":[{"JWT-auth":[]}],"summary":"Kill all sessions except current","tags":["Account"]}},"/account/security/sessions/{sessionId}":{"delete":{"description":"Terminates a specific session by deleting all authentication records for that IP address. You cannot kill your current session using this endpoint.","operationId":"killSession","parameters":[{"name":"sessionId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"Session killed successfully","content":{"application/json":{"example":{"success":true,"message":"Session killed successfully"}}}},"400":{"description":"Cannot kill current session"},"401":{"description":"Unauthorized - Invalid token"},"404":{"description":"Session not found"}},"security":[{"JWT-auth":[]}],"summary":"Kill a specific session","tags":["Account"]}},"/account/security/login-history":{"get":{"description":"Returns paginated login history with authentication attempts, including both successful and failed logins with geolocation data. Admins can pass userId query param to view other users.","operationId":"getLoginHistory","parameters":[{"name":"userId","required":false,"in":"query","description":"User ID (admin only) to view another user's history","schema":{"type":"string"}},{"name":"limit","required":false,"in":"query","description":"Number of results (default: 50)","schema":{"type":"number"}},{"name":"offset","required":false,"in":"query","description":"Offset for pagination (default: 0)","schema":{"type":"number"}},{"name":"success","required":false,"in":"query","description":"Filter by success status","schema":{"type":"boolean"}}],"responses":{"200":{"description":"Login history retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoginHistoryResponseDto"},"example":{"entries":[{"_id":"507f1f77bcf86cd799439011","accountId":"psx_abc123","success":true,"ip":"203.0.113.42","country":"US","countryName":"United States","city":"New York","userAgent":"Mozilla/5.0...","timestamp":"2025-01-15T15:30:00Z"},{"_id":"507f1f77bcf86cd799439022","accountId":"psx_abc123","success":false,"errorMessage":"Invalid credentials","ip":"198.51.100.99","country":"CN","countryName":"China","city":"Beijing","userAgent":"curl/7.68.0","timestamp":"2025-01-15T14:20:00Z"}],"total":247,"limit":50,"offset":0}}}},"401":{"description":"Unauthorized - Invalid token"}},"security":[{"JWT-auth":[]}],"summary":"Get login history","tags":["Account"]}},"/unsubscribe":{"get":{"operationId":"getPreferences","parameters":[{"name":"token","required":true,"in":"query","description":"Unsubscribe token from email link","schema":{"type":"string"}}],"responses":{"200":{"description":"Email preferences retrieved successfully","content":{"application/json":{"schema":{"type":"object","properties":{"subscriptions":{"type":"object","properties":{"marketing":{"type":"boolean"},"bandwidth":{"type":"boolean"},"portExpiring":{"type":"boolean"},"portRotation":{"type":"boolean"},"accountUpdates":{"type":"boolean"},"supportReplies":{"type":"boolean"}}},"unsubscribedFromAll":{"type":"boolean"}}}}}},"404":{"description":"Invalid unsubscribe token"}},"summary":"Get email preferences via unsubscribe token","tags":["Public - Email Preferences"]},"patch":{"operationId":"updatePreferences","parameters":[{"name":"token","required":true,"in":"query","description":"Unsubscribe token from email link","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"marketing":{"type":"boolean"},"bandwidth":{"type":"boolean"},"portExpiring":{"type":"boolean"},"portRotation":{"type":"boolean"}}}}}},"responses":{"200":{"description":"Email preferences updated successfully"},"404":{"description":"Invalid unsubscribe token"}},"summary":"Update email preferences via unsubscribe token","tags":["Public - Email Preferences"]}},"/unsubscribe/all":{"post":{"operationId":"unsubscribeAll","parameters":[{"name":"token","required":true,"in":"query","description":"Unsubscribe token from email link","schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully unsubscribed from all emails","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"message":{"type":"string"}}}}}},"404":{"description":"Invalid unsubscribe token"}},"summary":"Unsubscribe from all emails (one-click)","tags":["Public - Email Preferences"]}},"/unsubscribe/resubscribe":{"post":{"operationId":"resubscribe","parameters":[{"name":"token","required":true,"in":"query","description":"Unsubscribe token from email link","schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully resubscribed to emails"},"404":{"description":"Invalid unsubscribe token"}},"summary":"Resubscribe to emails","tags":["Public - Email Preferences"]}},"/devices/availability":{"get":{"operationId":"getAvailability","parameters":[],"responses":{"200":{"description":"Device availability grouped by country and carrier"}},"security":[{"JWT-auth":[]}],"summary":"Get live device availability by country and carrier (public, no auth)","tags":["Devices"]}},"/countries/with-devices":{"get":{"operationId":"findCountriesWithDevices","parameters":[{"name":"isPrivate","required":false,"in":"query","description":"Filter by private devices only (true/false)","schema":{"type":"boolean"}},{"name":"userId","required":false,"in":"query","description":"User ID to filter available countries (admins only)","schema":{}}],"responses":{"200":{"description":"Countries with available devices and their free device count","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"_id":{"type":"string","example":"507f1f77bcf86cd799439011"},"name":{"type":"string","example":"United States"},"code":{"type":"string","example":"US"},"iso3":{"type":"string","example":"USA"},"phoneCode":{"type":"string","example":"+1"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"freeDeviceCount":{"type":"number","example":5,"description":"Number of available devices in this country"}}}}}}}},"security":[{"JWT-auth":[]}],"summary":"Get countries that have available devices for port creation","tags":["Countries"]}},"/cities/country/{countryId}":{"get":{"operationId":"findByCountry","parameters":[{"name":"countryId","required":true,"in":"path","description":"Country ID","schema":{"type":"string"}},{"name":"isPrivate","required":false,"in":"query","description":"Filter by private devices only (true/false)","schema":{"type":"boolean"}},{"name":"userId","required":false,"in":"query","description":"User ID to filter available cities (admins only)","schema":{}},{"name":"withDevice","required":false,"in":"query","description":"Include free device count for each city (default: true)","schema":{"type":"boolean"}}],"responses":{"200":{"description":"Cities with available devices in the specified country","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"_id":{"type":"string"},"name":{"type":"string"},"countryId":{"type":"object","properties":{"_id":{"type":"string"},"name":{"type":"string"},"code":{"type":"string"}}},"stateProvince":{"type":"string"},"region":{"type":"string"},"latitude":{"type":"string"},"longitude":{"type":"string"},"timezone":{"type":"string"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"freeDeviceCount":{"type":"number","example":3,"description":"Number of available devices in this city"}}}}}}},"404":{"description":"Country not found"}},"security":[{"JWT-auth":[]}],"summary":"Get cities with available devices in a specific country","tags":["Cities"]}},"/carriers/country/{countryId}":{"get":{"operationId":"findByCountry","parameters":[{"name":"countryId","required":true,"in":"path","description":"Country ID","schema":{"type":"string"}},{"name":"isPrivate","required":false,"in":"query","description":"Filter by private devices only (true/false)","schema":{"type":"boolean"}},{"name":"userId","required":false,"in":"query","description":"User ID to filter available carriers (admins only)","schema":{}},{"name":"cityId","required":false,"in":"query","description":"Filter carriers by city (only returns carriers with devices in this city)","schema":{}},{"name":"withDevice","required":false,"in":"query","description":"Include free device count for each carrier (default: true)","schema":{"type":"boolean"}}],"responses":{"200":{"description":"Carriers with available devices in the specified country","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"_id":{"type":"string"},"name":{"type":"string"},"countryId":{"type":"object","properties":{"_id":{"type":"string"},"name":{"type":"string"},"code":{"type":"string"}}},"code":{"type":"string"},"mcc":{"type":"string"},"mnc":{"type":"string"},"brand":{"type":"string"},"website":{"type":"string"},"technology":{"type":"string"},"isActive":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"freeDeviceCount":{"type":"number","example":3,"description":"Number of available devices for this carrier"}}}}}}},"404":{"description":"Country not found"}},"security":[{"JWT-auth":[]}],"summary":"Get carriers with available devices in a specific country","tags":["Carriers"]}},"/ports":{"post":{"operationId":"createPort","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatePortDto"}}}},"responses":{"201":{"description":"Port successfully created with all connection details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PortResponseDto"},"example":{"_id":"507f1f77bcf86cd799439011","deviceId":"507f1f77bcf86cd799439012","customerId":"507f1f77bcf86cd799439013","httpPort":45123,"socksPort":45124,"serverIp":"192.168.1.100","proxyLogin":"user_abc123def456","proxyPassword":"SecurePass123!","createdAt":"2023-10-13T10:30:00.000Z","updatedAt":"2023-10-13T10:30:00.000Z"}}}},"400":{"description":"Bad request - No free ports available or invalid location/carrier combination"},"401":{"description":"Unauthorized - JWT token missing or invalid"},"403":{"description":"Forbidden - Admin or Customer role required"},"429":{"description":"Too Many Requests - Rate limited to 1 port creation per 20 seconds"}},"security":[{"JWT-auth":[]}],"summary":"Create a new port","tags":["Ports"]},"get":{"operationId":"getUserPorts","parameters":[],"responses":{"200":{"description":"List of all user ports with complete connection details including populated customer and device information","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PortResponseDto"}},"example":[{"_id":"507f1f77bcf86cd799439011","deviceId":"507f1f77bcf86cd799439012","customerId":"507f1f77bcf86cd799439013","httpPort":45123,"socksPort":45124,"serverIp":"192.168.1.100","proxyLogin":"user_abc123def456","proxyPassword":"SecurePass123!","createdAt":"2023-10-13T10:30:00.000Z","updatedAt":"2023-10-13T10:30:00.000Z","customer":{"_id":"507f1f77bcf86cd799439013","email":"user@example.com","role":"customer","name":"John Doe","organization":"Example Corp"},"device":{"_id":"507f1f77bcf86cd799439012","type":"phone","name":"Device 1","imei":"123456789012345","status":"active"}},{"_id":"507f1f77bcf86cd799439021","deviceId":"507f1f77bcf86cd799439022","customerId":"507f1f77bcf86cd799439013","httpPort":45223,"socksPort":45224,"serverIp":"192.168.1.101","proxyLogin":"user_xyz789uvw012","proxyPassword":"AnotherPass456!","createdAt":"2023-10-13T11:15:00.000Z","updatedAt":"2023-10-13T11:15:00.000Z","customer":{"_id":"507f1f77bcf86cd799439013","email":"user@example.com","role":"customer","name":"John Doe","organization":"Example Corp"},"device":{"_id":"507f1f77bcf86cd799439022","type":"modem","name":"Device 2","imei":"987654321098765","status":"active"}}]}}},"401":{"description":"Unauthorized - JWT token missing or invalid"},"403":{"description":"Forbidden - Admin or Customer role required"}},"security":[{"JWT-auth":[]}],"summary":"Get all user ports","tags":["Ports"]}},"/ports/bulk":{"post":{"operationId":"bulkCreatePorts","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkCreatePortDto"}}}},"responses":{"201":{"description":"Bulk port creation result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkCreatePortResultDto"},"example":{"total":3,"success":2,"failed":1,"created":[{"_id":"...","name":"psx_...","httpPort":8001,"socksPort":5001},{"_id":"...","name":"psx_...","httpPort":8002,"socksPort":5002}],"errors":[{"index":2,"error":"No suitable device available for port creation"}]}}}},"400":{"description":"Bad request - Invalid data or insufficient port slots/balance"},"401":{"description":"Unauthorized - JWT token missing or invalid"},"403":{"description":"Forbidden - Admin or Customer role required"}},"security":[{"JWT-auth":[]}],"summary":"Create multiple ports at once (max 50 ports per request)","tags":["Ports"]}},"/ports/bulk-smart":{"post":{"description":"Creates multiple ports (up to 50) with intelligent device allocation. Maximum 3 ports per device. Shows real-time progress.","operationId":"bulkCreatePortsSmart","parameters":[],"responses":{"201":{"description":"Bulk port creation complete with progress details"}},"security":[{"JWT-auth":[]}],"summary":"Smart bulk port creation with automatic device allocation","tags":["Ports"]}},"/ports/bulk-smart/max-available":{"get":{"operationId":"getMaxAvailablePorts","parameters":[{"name":"country","required":true,"in":"query","schema":{"type":"string"}},{"name":"isPrivate","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"JWT-auth":[]}],"summary":"Get maximum available ports for smart bulk creation","tags":["Ports"]}},"/ports/{id}":{"delete":{"operationId":"deletePort","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"Port successfully deleted and removed from user account","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeletePortResponseDto"},"example":{"message":"Port deleted successfully"}}}},"401":{"description":"Unauthorized - JWT token missing or invalid"},"403":{"description":"Forbidden - Admin or Customer role required"},"404":{"description":"Port not found or does not belong to the current user"}},"security":[{"JWT-auth":[]}],"summary":"Delete a port","tags":["Ports"]},"get":{"description":"Retrieve detailed information about a specific port including device info, credentials, rotation settings, and traffic usage.","operationId":"getPortById","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"Port details retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PortResponseDto"},"example":{"_id":"507f1f77bcf86cd799439011","name":"psx_abc123_xyz789","displayName":"Proxy #1","httpPort":45123,"socksPort":45124,"login":"user_abc123","password":"securePass123","serverIp":"192.168.1.100","deviceId":{"_id":"507f1f77bcf86cd799439012","imei":"354160112983279","countryId":{"name":"United States","code":"US"},"carrierId":{"name":"Verizon"},"regionId":{"name":"New York"}},"expiresAt":1697193600000,"suspended":false,"osFingerprint":"","rotationToken":"a1b2c3d4e5f6789012345678abcdef00","rotationSettings":{"enabled":false,"intervalSeconds":1200,"matchCarrier":false,"matchCity":false,"rotationCount":0},"usedTraffic":1024000,"createdAt":"2023-10-13T10:30:00.000Z","updatedAt":"2023-10-13T10:30:00.000Z"}}}},"401":{"description":"Unauthorized - JWT token or API Key missing/invalid"},"403":{"description":"Forbidden - Insufficient permissions"},"404":{"description":"Port not found or does not belong to the current user"}},"security":[{"JWT-auth":[]}],"summary":"Get single port details by ID","tags":["Ports"]}},"/ports/{id}/credentials":{"put":{"operationId":"updatePortCredentials","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdatePortCredentialsDto"}}}},"responses":{"200":{"description":"Port credentials updated successfully with new login and password","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PortResponseDto"},"example":{"_id":"507f1f77bcf86cd799439011","deviceId":"507f1f77bcf86cd799439012","customerId":"507f1f77bcf86cd799439013","httpPort":45123,"socksPort":45124,"serverIp":"192.168.1.100","proxyLogin":"new_user_login","proxyPassword":"NewSecurePass123!","createdAt":"2023-10-13T10:30:00.000Z","updatedAt":"2023-10-13T11:45:00.000Z"}}}},"401":{"description":"Unauthorized - JWT token missing or invalid"},"403":{"description":"Forbidden - Admin or Customer role required"},"404":{"description":"Port not found or does not belong to the current user"}},"security":[{"JWT-auth":[]}],"summary":"Update port credentials","tags":["Ports"]}},"/ports/{id}/os-fingerprint":{"patch":{"operationId":"updateOsFingerprint","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateOsFingerprintDto"}}}},"responses":{"200":{"description":"OS fingerprint updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PortResponseDto"}}}},"400":{"description":"Bad request - Invalid OS fingerprint value or server does not support p0f"},"401":{"description":"Unauthorized - JWT token missing or invalid"},"403":{"description":"Forbidden - Admin or Customer role required"},"404":{"description":"Port not found or does not belong to the current user"}},"security":[{"JWT-auth":[]}],"summary":"Update OS fingerprint (p0f) for a port - changes how traffic appears to be from different OS","tags":["Ports"]}},"/ports/{id}/os-fingerprints":{"get":{"operationId":"getAvailableOsFingerprints","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"List of available OS fingerprints","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"value":{"type":"string","example":"windows:1"},"label":{"type":"string","example":"Windows 10"}}}}}}},"400":{"description":"Bad request - Server does not support p0f"},"404":{"description":"Port not found or does not belong to the current user"}},"security":[{"JWT-auth":[]}],"summary":"Get available OS fingerprints for this port's server","tags":["Ports"]}},"/ports/{id}/openvpn":{"get":{"description":"Proxies the OpenVPN profile download through the API to hide the actual server IP from customers. Returns an .ovpn file that can be imported into any OpenVPN client.","operationId":"downloadOpenVpnProfile","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"OpenVPN profile file (.ovpn)","content":{"application/x-openvpn-profile":{"schema":{"type":"string","format":"binary"}}}},"400":{"description":"Bad request - Port is not on a ProxySmart server"},"401":{"description":"Unauthorized - JWT token missing or invalid"},"403":{"description":"Forbidden - Admin or Customer role required"},"404":{"description":"Port not found or does not belong to the current user"},"500":{"description":"Failed to download OpenVPN profile from server"}},"security":[{"JWT-auth":[]}],"summary":"Download OpenVPN profile for a port","tags":["Ports"]}},"/ports/{id}/status":{"get":{"operationId":"getPortStatus","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"Port status information including online/offline status and last check time","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PortStatusResponseDto"},"example":{"status":"online","isActive":true,"lastChecked":"2023-10-13T12:00:00.000Z"}}}},"401":{"description":"Unauthorized - JWT token missing or invalid"},"403":{"description":"Forbidden - Admin or Customer role required"},"404":{"description":"Port not found or does not belong to the current user"}},"security":[{"JWT-auth":[]}],"summary":"Get port status","tags":["Ports"]}},"/ports/{id}/ip":{"get":{"operationId":"getPortIp","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"Port IP information including public and server IP addresses","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PortIpResponseDto"},"example":{"publicIp":"203.0.113.42","serverIp":"192.168.1.100"}}}},"401":{"description":"Unauthorized - JWT token missing or invalid"},"403":{"description":"Forbidden - Admin or Customer role required"},"404":{"description":"Port not found or does not belong to the current user"}},"security":[{"JWT-auth":[]}],"summary":"Get port IP information","tags":["Ports"]}},"/ports/{id}/test-speed":{"get":{"operationId":"testPortSpeed","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"Port speed test results including download/upload speeds and ping","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PortSpeedTestResponseDto"},"example":{"downloadSpeed":85,"uploadSpeed":32,"ping":45,"testTime":"2023-10-13T12:05:00.000Z"}}}},"401":{"description":"Unauthorized - JWT token missing or invalid"},"403":{"description":"Forbidden - Admin or Customer role required"},"404":{"description":"Port not found or does not belong to the current user"}},"security":[{"JWT-auth":[]}],"summary":"Test port speed","tags":["Ports"]}},"/ports/{id}/ping":{"get":{"operationId":"pingPort","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"Ping result with IP address and response time","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PortPingResponseDto"},"example":{"success":true,"ip":"203.0.113.42","responseTime":245,"testTime":"2023-10-13T12:05:00.000Z"}}}},"401":{"description":"Unauthorized - JWT token missing or invalid"},"403":{"description":"Forbidden - Admin or Customer role required"},"404":{"description":"Port not found or does not belong to the current user"}},"security":[{"JWT-auth":[]}],"summary":"Ping port to verify proxy connectivity and get IP","tags":["Ports"]}},"/ports/{id}/extend-time":{"post":{"operationId":"extendPortTime","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"description":"Number of hours to extend the port expiration","content":{"application/json":{"schema":{"type":"object","required":["hours"],"properties":{"hours":{"type":"number","description":"Hours to add to expiration time","example":24}}}}}},"responses":{"200":{"description":"Port expiration extended successfully","content":{"application/json":{"example":{"success":true,"message":"Port expiration extended by 24 hours","newExpiresAt":1697280000000}}}},"400":{"description":"Invalid hours value"},"401":{"description":"Unauthorized - JWT token missing or invalid"},"403":{"description":"Forbidden - Admin or Customer role required"},"404":{"description":"Port not found or does not belong to the current user"}},"security":[{"JWT-auth":[]}],"summary":"Extend the expiration time of a port and sync with ProxySmart","tags":["Ports"]}},"/ports/{id}/max-extend-hours":{"get":{"operationId":"getPortMaxExtendHours","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"Maximum extend hours info for the port","content":{"application/json":{"example":{"maxHoursAllowed":672,"currentExpiresAt":1697280000000,"maxExpiresAt":1699872000000,"subscriptionExpiresAt":1699872000000}}}},"401":{"description":"Unauthorized - JWT token missing or invalid"},"403":{"description":"Forbidden - Admin or Customer role required"},"404":{"description":"Port not found or does not belong to the current user"}},"security":[{"JWT-auth":[]}],"summary":"Get maximum hours that can be added to a port (based on user subscription expiration)","tags":["Ports"]}},"/ports/{id}/reconfigure":{"post":{"operationId":"reconfigurePort","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReconfigurePortDto"}}}},"responses":{"200":{"description":"Port reconfigured successfully with new device. Remaining time preserved.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PortResponseDto"},"example":{"_id":"507f1f77bcf86cd799439111","deviceId":"507f1f77bcf86cd799439222","customerId":"507f1f77bcf86cd799439013","httpPort":45223,"socksPort":45224,"serverIp":"192.168.1.102","proxyLogin":"user_new123","proxyPassword":"NewPass123!","expiresAt":1697366400000,"createdAt":"2023-10-13T10:30:00.000Z","updatedAt":"2023-10-14T12:30:00.000Z"}}}},"400":{"description":"No devices available with the selected configuration"},"401":{"description":"Unauthorized - JWT token missing or invalid"},"403":{"description":"Forbidden - Admin or Customer role required"},"404":{"description":"Port not found or does not belong to the current user"},"429":{"description":"Too Many Requests - Rate limited to 3 requests per 2 minutes"}},"security":[{"JWT-auth":[]}],"summary":"Reconfigure a port with new country/city/carrier (rate limited: 3 requests per 2 minutes)","tags":["Ports"]}},"/ports/{id}/rotate":{"post":{"description":"Rotates the port to a different modem in the same country, giving a new IP address. Credentials and expiration are preserved. Rate limiting is enforced per-port based on successful rotations.","operationId":"rotatePort","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RotatePortDto"}}}},"responses":{"200":{"description":"Port rotated successfully to a new device","content":{"application/json":{"example":{"success":true,"portId":"507f1f77bcf86cd799439011","oldDeviceId":"507f1f77bcf86cd799439012","newDeviceId":"507f1f77bcf86cd799439022","oldIp":"203.0.113.42","newIp":"203.0.113.99","rotationDurationMs":1234,"rotationCount":5,"message":"Port rotated successfully"}}}},"400":{"description":"No devices available for rotation, rate limited, port expired/suspended, or other validation error"},"404":{"description":"Port not found or does not belong to the current user"}},"security":[{"JWT-auth":[]}],"summary":"Manually rotate a port to a new device (rate limited: 1 rotation per 5 minutes)","tags":["Ports"]}},"/ports/{id}/replace":{"post":{"description":"Deletes the current port (if on inactive device) and creates a new one on an active device in the same location. Useful when device goes offline.","operationId":"replacePort","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"Port replaced successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PortResponseDto"},"example":{"_id":"507f1f77bcf86cd799439099","displayName":"Proxy #5","httpPort":45200,"socksPort":45201,"serverIp":"192.168.1.101","proxyLogin":"user_newdevice","proxyPassword":"NewPassword456!","message":"Port successfully replaced on active device"}}}},"400":{"description":"No active devices available for replacement"},"404":{"description":"Port not found or does not belong to the current user"}},"security":[{"JWT-auth":[]}],"summary":"Replace port with new one on active device","tags":["Ports"]}},"/ports/{id}/reset-ip":{"post":{"description":"Triggers ProxySmart airplane mode toggle to get a new IP address. Only works on private device ports (psx_prvt_ prefix). Rate limited to 1 reset per 30 seconds.","operationId":"resetIp","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"IP reset triggered successfully","content":{"application/json":{"example":{"success":true,"message":"IP reset triggered. New IP should be available in 10-30 seconds.","portId":"507f1f77bcf86cd799439011"}}}},"400":{"description":"Port is not on a private device or IP reset failed"},"404":{"description":"Port not found or does not belong to the current user"},"429":{"description":"Rate limited - must wait 30 seconds between IP resets"}},"security":[{"JWT-auth":[]}],"summary":"Reset IP via airplane mode (private devices only)","tags":["Ports"]}},"/ports/{id}/regenerate-rotation-token":{"post":{"description":"Generates a new secure token for the public rotation API. The old token will no longer work.","operationId":"regenerateRotationToken","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"New rotation token generated","content":{"application/json":{"schema":{"type":"object","properties":{"rotationToken":{"type":"string","example":"a1b2c3d4e5f6789012345678abcdef00"},"rotationUrl":{"type":"string","example":"https://api.proxies.sx/v1/rotate/a1b2c3d4e5f6789012345678abcdef00"}}}}}},"404":{"description":"Port not found or does not belong to the current user"}},"security":[{"JWT-auth":[]}],"summary":"Regenerate the public rotation API token for a port","tags":["Ports"]}},"/ports/{id}/rotation-settings":{"get":{"operationId":"getRotationSettings","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"Port rotation settings","content":{"application/json":{"example":{"enabled":true,"intervalSeconds":1200,"lastRotatedAt":"2023-10-13T12:00:00.000Z","rotationCount":5,"matchCarrier":false,"matchCity":false,"excludedDeviceIds":[]}}}},"404":{"description":"Port not found or does not belong to the current user"}},"security":[{"JWT-auth":[]}],"summary":"Get rotation settings for a port","tags":["Ports"]},"patch":{"operationId":"updateRotationSettings","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateRotationSettingsDto"}}}},"responses":{"200":{"description":"Rotation settings updated successfully","content":{"application/json":{"example":{"_id":"507f1f77bcf86cd799439011","rotationSettings":{"enabled":true,"intervalSeconds":900,"lastRotatedAt":null,"rotationCount":0,"matchCarrier":true,"matchCity":false,"excludedDeviceIds":[]}}}}},"400":{"description":"Invalid settings (e.g., intervalSeconds < 60 for private, < 300 for shared)"},"404":{"description":"Port not found or does not belong to the current user"}},"security":[{"JWT-auth":[]}],"summary":"Update rotation settings for a port","tags":["Ports"]}},"/ports/{id}/rotation-history":{"get":{"operationId":"getRotationHistory","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"limit","required":false,"in":"query","description":"Number of records to return (default: 20)","schema":{"type":"number"}},{"name":"offset","required":false,"in":"query","description":"Number of records to skip (default: 0)","schema":{"type":"number"}}],"responses":{"200":{"description":"Port rotation history","content":{"application/json":{"example":{"rotations":[{"_id":"507f1f77bcf86cd799439099","portId":"507f1f77bcf86cd799439011","fromDeviceId":"507f1f77bcf86cd799439012","toDeviceId":"507f1f77bcf86cd799439022","fromIp":"203.0.113.42","toIp":"203.0.113.99","triggerType":"manual","success":true,"rotationDurationMs":1234,"country":"Germany","carrier":"Vodafone","city":"Berlin","createdAt":"2023-10-13T12:00:00.000Z"}],"total":5}}}},"404":{"description":"Port not found or does not belong to the current user"}},"security":[{"JWT-auth":[]}],"summary":"Get rotation history for a port","tags":["Ports"]}},"/ports/{id}/can-rotate":{"get":{"operationId":"canRotate","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"Rotation availability status","content":{"application/json":{"example":{"canRotate":true,"availableDevices":5}}}},"404":{"description":"Port not found or does not belong to the current user"}},"security":[{"JWT-auth":[]}],"summary":"Check if a port can be rotated","tags":["Ports"]}},"/ports/{id}/auto-renewal":{"get":{"operationId":"getAutoRenewalSettings","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"Auto-renewal settings","content":{"application/json":{"example":{"enabled":true,"source":"balance","renewalDays":30,"lastRenewalAt":null,"nextRenewalAt":"2024-01-15T12:00:00.000Z","failedAttempts":0,"lastFailureReason":null,"totalAutoRenewals":2}}}},"404":{"description":"Port not found"}},"security":[{"JWT-auth":[]}],"summary":"Get auto-renewal settings for a port","tags":["Ports"]},"patch":{"operationId":"updateAutoRenewalSettings","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateAutoRenewalDto"}}}},"responses":{"200":{"description":"Auto-renewal settings updated successfully","content":{"application/json":{"example":{"enabled":true,"source":"stripe","renewalDays":30,"lastRenewalAt":null,"nextRenewalAt":"2024-01-15T12:00:00.000Z","failedAttempts":0,"lastFailureReason":null,"totalAutoRenewals":0}}}},"400":{"description":"Invalid settings"},"404":{"description":"Port not found"}},"security":[{"JWT-auth":[]}],"summary":"Update auto-renewal settings for a port","tags":["Ports"]}},"/rotate/{token}":{"get":{"description":"Public endpoint for instant IP rotation.\n    - **Private devices**: Triggers airplane mode (new IP in 10-30 seconds)\n    - **Shared devices**: Switches to a different modem (background process)\n    Rate limited to 10 requests/minute. Per-port cooldown: 60s (private) or 5min (shared).","operationId":"rotateByToken","parameters":[{"name":"token","required":true,"in":"path","description":"Secure rotation token (32-character hex string)","schema":{"example":"a1b2c3d4e5f6789012345678abcdef00","type":"string"}}],"responses":{"200":{"description":"Rotation triggered successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"IP rotation triggered. New IP available in 10-30 seconds."},"rotationType":{"type":"string","enum":["airplane_mode","device_switch"],"example":"airplane_mode"},"portName":{"type":"string","example":"Proxy #1"},"cooldownSeconds":{"type":"number","example":60}}}}}},"400":{"description":"Rotation not allowed (cooldown, suspended, etc.)"},"404":{"description":"Invalid or expired rotation token"},"429":{"description":"Too many requests - rate limited"}},"summary":"Rotate port to get new IP via secure token","tags":["Public Rotation API"]}},"/billing/pricing":{"get":{"operationId":"getPricing","parameters":[],"responses":{"200":{"description":"Pricing information retrieved successfully","content":{"application/json":{"schema":{"type":"object","properties":{"basePrices":{"type":"object","properties":{"shared":{"type":"number","example":4},"private":{"type":"number","example":8}}},"volumeDiscounts":{"type":"array","items":{"type":"object","properties":{"minGB":{"type":"number"},"maxGB":{"type":"number","nullable":true},"discountPercent":{"type":"number"}}}},"slotTiers":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"minGB":{"type":"number"},"sharedSlots":{"type":"number"},"privateSlots":{"type":"number"}}}},"userTierInfo":{"type":"object","nullable":true,"properties":{"currentTier":{"type":"object"},"nextTier":{"type":"object","nullable":true},"cumulativeGB":{"type":"number"},"gbToNextTier":{"type":"number","nullable":true},"sharedSlotLimit":{"type":"number"},"privateSlotLimit":{"type":"number"}}}}}}}}},"security":[{"JWT-auth":[]}],"summary":"Get pricing information, volume discounts, and slot tiers","tags":["Billing"]}},"/billing/calculate-price":{"get":{"operationId":"calculatePrice","parameters":[{"name":"amount","required":true,"in":"query","description":"Amount of GB to calculate price for","schema":{"type":"number"}},{"name":"isPrivate","required":false,"in":"query","description":"Calculate for private traffic (default: false)","schema":{"type":"boolean"}}],"responses":{"200":{"description":"Price calculation returned successfully","content":{"application/json":{"schema":{"type":"object","properties":{"basePrice":{"type":"number","description":"Base price per GB"},"discountPercent":{"type":"number","description":"Applied discount percentage"},"pricePerGB":{"type":"number","description":"Effective price per GB after discount"},"totalPrice":{"type":"number","description":"Total price for the amount"},"amount":{"type":"number","description":"Amount of GB"},"isPrivate":{"type":"boolean"}}}}}}},"security":[{"JWT-auth":[]}],"summary":"Calculate price for a given GB amount with volume discounts","tags":["Billing"]}},"/billing/payments":{"get":{"operationId":"getPayments","parameters":[{"name":"userId","required":false,"in":"query","description":"Filter by user ID (Admin only)","schema":{"type":"string"}},{"name":"coin","required":false,"in":"query","description":"Filter by coin type","schema":{"type":"string"}},{"name":"address","required":false,"in":"query","description":"Filter by crypto address","schema":{"type":"string"}},{"name":"day","required":false,"in":"query","description":"Filter by day (-1 = current day)","schema":{"type":"number"}},{"name":"month","required":false,"in":"query","description":"Filter by month (-1 = current month)","schema":{"type":"number"}},{"name":"startDate","required":false,"in":"query","description":"Filter by start date (timestamp)","schema":{"type":"number"}},{"name":"endDate","required":false,"in":"query","description":"Filter by end date (timestamp)","schema":{"type":"number"}}],"responses":{"200":{"description":"Payments retrieved successfully","content":{"application/json":{"example":[{"_id":"507f1f77bcf86cd799439011","userId":"507f1f77bcf86cd799439013","coin":"btc","amount":0.001,"amountInUSD":65.5,"status":"confirmed","network":"mainnet","address":"1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa","txId":"6c44dc339b5a66a8e8d5b8d65d3b6e5f1d8e7a9b2c3d4e5f6a7b8c9d0e1f2a3b","confirmations":6,"createdAt":1697192400000,"updatedAt":1697192400000},{"_id":"507f1f77bcf86cd799439022","userId":"507f1f77bcf86cd799439013","coin":"usdt","amount":100,"amountInUSD":100,"status":"confirmed","network":"ERC20","address":"0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb","txId":"0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef","confirmations":12,"createdAt":1697106000000,"updatedAt":1697106000000},{"_id":"507f1f77bcf86cd799439033","userId":"507f1f77bcf86cd799439013","coin":"usd","amount":5000,"amountInUSD":50,"status":"succeeded","sessionId":"cs_test_a1b2c3d4e5f6g7h8i9j0","paymentIntentId":"pi_1A2B3C4D5E6F7G8H","metadata":{"plan":"premium"},"createdAt":1697019600000,"updatedAt":1697019600000}]}}},"401":{"description":"Unauthorized - Invalid token"},"403":{"description":"Forbidden - Insufficient permissions"}},"security":[{"JWT-auth":[]}],"summary":"Get payments (Admin: all payments, Customer: own payments only)","tags":["Billing"]}},"/billing/purchase-ports":{"post":{"operationId":"purchasePorts","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID (Admin only - optional)"},"amount":{"type":"number","description":"Number of ports to purchase"},"chargeUser":{"type":"boolean","description":"Admin only: true = charge user balance, false = free addition (default: false)"}},"required":["amount"]}}}},"responses":{"201":{"description":"Ports purchase successfully created","content":{"application/json":{"example":{"_id":"507f1f77bcf86cd799439011","userId":"507f1f77bcf86cd799439013","tariffId":"507f1f77bcf86cd799439014","type":"ports","amount":10,"price":100,"purchaseWithBalance":true,"createdAt":1697192400000,"updatedAt":1697192400000}}}},"400":{"description":"Bad request - Insufficient balance or invalid amount"},"401":{"description":"Unauthorized - Invalid token"},"403":{"description":"Forbidden - Insufficient permissions"}},"security":[{"JWT-auth":[]}],"summary":"Purchase ports (Admin can purchase for any user, Customer purchases for themselves)","tags":["Billing"]}},"/billing/purchase-traffic":{"post":{"operationId":"purchaseTraffic","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID (Admin only - optional)"},"amount":{"type":"number","description":"Amount of traffic to purchase"},"chargeUser":{"type":"boolean","description":"Admin only: true = charge user balance, false = free addition (default: false)"}},"required":["amount"]}}}},"responses":{"201":{"description":"Traffic purchase successfully created","content":{"application/json":{"example":{"_id":"507f1f77bcf86cd799439011","userId":"507f1f77bcf86cd799439013","tariffId":"507f1f77bcf86cd799439014","type":"traffic","amount":1000,"price":50,"purchaseWithBalance":true,"createdAt":1697192400000,"updatedAt":1697192400000}}}},"400":{"description":"Bad request - Insufficient balance or invalid amount"},"401":{"description":"Unauthorized - Invalid token"},"403":{"description":"Forbidden - Insufficient permissions"}},"security":[{"JWT-auth":[]}],"summary":"Purchase traffic (Admin can purchase for any user, Customer purchases for themselves)","tags":["Billing"]}},"/billing/purchase-ports-with-pending-payment":{"post":{"operationId":"purchasePortsWithPendingPayment","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID (Admin only - optional)"},"amount":{"type":"number","description":"Number of ports to purchase"}},"required":["amount"]}}}},"responses":{"201":{"description":"Ports purchase with pending payment successfully created","content":{"application/json":{"example":{"purchaseId":"507f1f77bcf86cd799439011"}}}},"400":{"description":"Bad request - Invalid amount"},"401":{"description":"Unauthorized - Invalid token"},"403":{"description":"Forbidden - Insufficient permissions"}},"security":[{"JWT-auth":[]}],"summary":"Purchase ports with pending payment (creates purchase without balance check)","tags":["Billing"]}},"/billing/purchase-traffic-with-pending-payment":{"post":{"operationId":"purchaseTrafficWithPendingPayment","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID (Admin only - optional)"},"amount":{"type":"number","description":"Amount of traffic to purchase"}},"required":["amount"]}}}},"responses":{"201":{"description":"Traffic purchase with pending payment successfully created","content":{"application/json":{"example":{"purchaseId":"507f1f77bcf86cd799439011"}}}},"400":{"description":"Bad request - Invalid amount"},"401":{"description":"Unauthorized - Invalid token"},"403":{"description":"Forbidden - Insufficient permissions"}},"security":[{"JWT-auth":[]}],"summary":"Purchase traffic with pending payment (creates purchase without balance check)","tags":["Billing"]}},"/billing/purchase-ports-private-with-pending-payment":{"post":{"operationId":"purchasePortsPrivateWithPendingPayment","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID (Admin only - optional)"},"amount":{"type":"number","description":"Number of private port slots to purchase"}},"required":["amount"]}}}},"responses":{"201":{"description":"Private ports purchase with pending payment successfully created"},"400":{"description":"Bad request - Invalid amount"}},"security":[{"JWT-auth":[]}],"summary":"Purchase PRIVATE port slots with pending payment (creates purchase without balance check)","tags":["Billing"]}},"/billing/purchase-traffic-private-with-pending-payment":{"post":{"operationId":"purchaseTrafficPrivateWithPendingPayment","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID (Admin only - optional)"},"amount":{"type":"number","description":"Amount of private traffic to purchase (GB)"}},"required":["amount"]}}}},"responses":{"201":{"description":"Private traffic purchase with pending payment successfully created"},"400":{"description":"Bad request - Invalid amount"}},"security":[{"JWT-auth":[]}],"summary":"Purchase PRIVATE traffic GB with pending payment (creates purchase without balance check)","tags":["Billing"]}},"/billing/purchase-ports-private":{"post":{"operationId":"purchasePortsPrivate","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID (Admin only - optional)"},"amount":{"type":"number","description":"Number of private port slots to purchase"},"chargeUser":{"type":"boolean","description":"Admin only: true = charge user balance, false = free addition (default: false)"}},"required":["amount"]}}}},"responses":{"201":{"description":"Private ports purchase successfully created"},"400":{"description":"Bad request - Insufficient balance or invalid amount"}},"security":[{"JWT-auth":[]}],"summary":"Purchase PRIVATE port slots (Admin can purchase for any user)","tags":["Billing"]}},"/billing/purchase-traffic-private":{"post":{"operationId":"purchaseTrafficPrivate","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"User ID (Admin only - optional)"},"amount":{"type":"number","description":"Amount of private traffic to purchase (GB)"},"chargeUser":{"type":"boolean","description":"Admin only: true = charge user balance, false = free addition (default: false)"}},"required":["amount"]}}}},"responses":{"201":{"description":"Private traffic purchase successfully created"},"400":{"description":"Bad request - Insufficient balance or invalid amount"}},"security":[{"JWT-auth":[]}],"summary":"Purchase PRIVATE traffic GB (Admin can purchase for any user)","tags":["Billing"]}},"/invoices":{"get":{"operationId":"findAll","parameters":[{"name":"userId","required":false,"in":"query","description":"Filter by user ID (Admin only)","schema":{"type":"string"}},{"name":"status","required":false,"in":"query","schema":{"enum":["draft","pending","paid","cancelled","refunded"],"type":"string"}},{"name":"startDate","required":false,"in":"query","schema":{"type":"number"}},{"name":"endDate","required":false,"in":"query","schema":{"type":"number"}},{"name":"page","required":false,"in":"query","description":"Page number (default: 1)","schema":{"type":"number"}},{"name":"limit","required":false,"in":"query","description":"Items per page (default: 20)","schema":{"type":"number"}}],"responses":{"200":{"description":"Invoices retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InvoiceListResponseDto"}}}}},"security":[{"JWT-auth":[]}],"summary":"Get invoices (Admin: all, Customer: own invoices)","tags":["Invoices"]}},"/invoices/my":{"get":{"operationId":"getMyInvoices","parameters":[{"name":"status","required":false,"in":"query","schema":{"enum":["draft","pending","paid","cancelled","refunded"],"type":"string"}},{"name":"page","required":false,"in":"query","schema":{"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"type":"number"}}],"responses":{"200":{"description":"User invoices retrieved","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InvoiceListResponseDto"}}}}},"security":[{"JWT-auth":[]}],"summary":"Get current user's invoices","tags":["Invoices"]}},"/invoices/stats":{"get":{"operationId":"getStats","parameters":[{"name":"userId","required":false,"in":"query","description":"User ID (Admin only)","schema":{"type":"string"}}],"responses":{"200":{"description":"Invoice statistics","content":{"application/json":{"schema":{"type":"object","properties":{"totalInvoices":{"type":"number"},"totalPaid":{"type":"number"},"totalPending":{"type":"number"},"totalAmount":{"type":"number"},"paidAmount":{"type":"number"},"pendingAmount":{"type":"number"}}}}}}},"security":[{"JWT-auth":[]}],"summary":"Get invoice statistics for user","tags":["Invoices"]}},"/invoices/{id}":{"get":{"operationId":"findById","parameters":[{"name":"id","required":true,"in":"path","description":"Invoice ID","schema":{"type":"string"}}],"responses":{"200":{"description":"Invoice details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InvoiceResponseDto"}}}},"404":{"description":"Invoice not found"}},"security":[{"JWT-auth":[]}],"summary":"Get invoice by ID","tags":["Invoices"]}},"/invoices/number/{invoiceNumber}":{"get":{"operationId":"findByNumber","parameters":[{"name":"invoiceNumber","required":true,"in":"path","description":"Invoice number (e.g., INV-2025-000001)","schema":{"type":"string"}}],"responses":{"200":{"description":"Invoice details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InvoiceResponseDto"}}}},"404":{"description":"Invoice not found"}},"security":[{"JWT-auth":[]}],"summary":"Get invoice by invoice number","tags":["Invoices"]}},"/v1/messages":{"post":{"operationId":"send","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateMessageDto"}}}},"responses":{"201":{"description":"Message sent successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageDto"}}}},"400":{"description":"Invalid input data"},"401":{"description":"Unauthorized - Invalid token"}},"security":[{"JWT-auth":[]}],"summary":"Send a message","tags":["Messages"]}},"/v1/messages/inbox":{"get":{"operationId":"inbox","parameters":[],"responses":{"200":{"description":"Inbox retrieved","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedMessagesDto"}}}},"401":{"description":"Unauthorized - Invalid token"}},"security":[{"JWT-auth":[]}],"summary":"Get inbox messages","tags":["Messages"]}},"/v1/messages/conversation/{userId}":{"get":{"operationId":"conversation","parameters":[{"name":"userId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"Conversation retrieved","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedMessagesDto"}}}},"401":{"description":"Unauthorized - Invalid token"}},"security":[{"JWT-auth":[]}],"summary":"Get conversation with a specific user","tags":["Messages"]}},"/v1/messages/{id}/read":{"patch":{"operationId":"markRead","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"Message marked as read","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageDto"}}}},"401":{"description":"Unauthorized - Invalid token"},"404":{"description":"Message not found"}},"security":[{"JWT-auth":[]}],"summary":"Mark message as read","tags":["Messages"]}},"/tariffs":{"get":{"operationId":"findAll","parameters":[],"responses":{"200":{"description":"Tariffs retrieved successfully","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TariffResponseDto"}}}}},"401":{"description":"Unauthorized - Invalid token or API key"},"403":{"description":"Forbidden - Insufficient permissions"}},"security":[{"JWT-auth":[]}],"summary":"Get all tariffs (Admin, Customer, Farmer, or API Key with ports:read scope)","tags":["Tariffs"]}},"/coingate/create-order":{"post":{"description":"Create a new crypto payment order. Returns a payment URL where the customer can select their preferred cryptocurrency and complete the payment on CoinGate's hosted checkout page.","operationId":"createOrder","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateOrderDto"}}}},"responses":{"201":{"description":"Order created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateOrderResponseDto"}}}},"400":{"description":"Invalid amount or crypto payments not configured"},"401":{"description":"Unauthorized"},"429":{"description":"Too many requests"}},"security":[{"JWT-auth":[]}],"summary":"Create crypto payment order","tags":["Crypto Payments (CoinGate)"]}},"/coingate/order/{orderId}":{"get":{"description":"Get the current status of a crypto payment order.","operationId":"getOrder","parameters":[{"name":"orderId","required":true,"in":"path","description":"Internal order ID (e.g., topup_abc123_1702134567890)","schema":{"type":"string"}}],"responses":{"200":{"description":"Order details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrderStatusDto"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Order not found"}},"security":[{"JWT-auth":[]}],"summary":"Get order status","tags":["Crypto Payments (CoinGate)"]}},"/coingate/history":{"get":{"description":"Get the user's crypto payment order history.","operationId":"getHistory","parameters":[],"responses":{"200":{"description":"Order history","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/OrderHistoryDto"}}}}},"401":{"description":"Unauthorized"}},"security":[{"JWT-auth":[]}],"summary":"Get crypto payment history","tags":["Crypto Payments (CoinGate)"]}},"/coingate/pending":{"get":{"description":"Get the user's pending crypto payment orders (new, pending, or confirming status).","operationId":"getPendingPayments","parameters":[],"responses":{"200":{"description":"Pending payments","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/OrderHistoryDto"}}}}},"401":{"description":"Unauthorized"}},"security":[{"JWT-auth":[]}],"summary":"Get pending crypto payments","tags":["Crypto Payments (CoinGate)"]}},"/coingate/cancel/{orderId}":{"post":{"description":"Cancel a pending crypto payment order. Only orders with \"new\" status (awaiting payment) can be canceled. Once payment has been sent, the order cannot be canceled.","operationId":"cancelOrder","parameters":[{"name":"orderId","required":true,"in":"path","description":"Internal order ID (e.g., topup_abc123_1702134567890)","schema":{"type":"string"}}],"responses":{"200":{"description":"Order canceled successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Payment canceled successfully. The CoinGate payment link will expire automatically."}}}}}},"400":{"description":"Order cannot be canceled (already paid or confirming)"},"401":{"description":"Unauthorized"},"404":{"description":"Order not found"}},"security":[{"JWT-auth":[]}],"summary":"Cancel a pending crypto payment","tags":["Crypto Payments (CoinGate)"]}},"/coingate/webhook":{"post":{"description":"Receives payment status updates from CoinGate. This endpoint is called by CoinGate servers when payment status changes.","operationId":"handleWebhook","parameters":[],"responses":{"200":{"description":"Callback processed successfully"},"403":{"description":"Unauthorized callback source"}},"summary":"CoinGate webhook callback","tags":["Crypto Payments (CoinGate)"]}},"/coingate/status":{"get":{"description":"Check if crypto payments are configured and available.","operationId":"getStatus","parameters":[],"responses":{"200":{"description":"Crypto payment status","content":{"application/json":{"schema":{"type":"object","properties":{"available":{"type":"boolean","example":true},"supportedCurrencies":{"type":"array","items":{"type":"string"},"example":["BTC","ETH","LTC","USDT","USDC"]}}}}}}},"summary":"Check crypto payment availability","tags":["Crypto Payments (CoinGate)"]}},"/stripe/create-payment-intent":{"post":{"operationId":"createPaymentIntent","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatePaymentIntentDto"}}}},"responses":{"201":{"description":"Payment intent successfully created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaymentIntentResponseDto"}}}},"400":{"description":"Invalid input data"}},"summary":"Create a payment intent","tags":["Stripe Payments"]}},"/stripe/setup-payment-intent":{"post":{"operationId":"setupPaymentIntent","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetupPaymentIntentDto"}}}},"responses":{"201":{"description":"Setup intent successfully created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetupPaymentIntentResponseDto"}}}},"400":{"description":"Invalid input data"}},"summary":"Setup payment intent for future payments","tags":["Stripe Payments"]}},"/stripe/cards/{cardId}/pay":{"post":{"operationId":"payUsingSavedCard","parameters":[{"name":"cardId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PayUsingSavedCardDto"}}}},"responses":{"200":{"description":"Payment processed successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PayUsingSavedCardResponseDto"}}}},"400":{"description":"Invalid input data"},"403":{"description":"Card does not belong to user"},"404":{"description":"Card not found"}},"summary":"Pay using a saved card","tags":["Stripe Payments"]}},"/stripe/cards/{cardId}/topup":{"post":{"operationId":"topUpUsingSavedCard","parameters":[{"name":"cardId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TopUpUsingSavedCardDto"}}}},"responses":{"200":{"description":"Top-up processed successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TopUpUsingSavedCardResponseDto"}}}},"400":{"description":"Invalid input data"},"403":{"description":"Card does not belong to user"},"404":{"description":"Card not found"}},"summary":"Top-up using a saved card","tags":["Stripe Payments"]}},"/stripe/cards":{"get":{"operationId":"getActiveCardList","parameters":[],"responses":{"200":{"description":"List of active cards returned","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ActiveCardInfoDto"}}}}}},"summary":"Get active saved cards for the authenticated customer","tags":["Stripe Payments"]}},"/stripe/cards/{cardId}":{"delete":{"operationId":"removeCard","parameters":[{"name":"cardId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"Card successfully removed"},"403":{"description":"Card does not belong to user"},"404":{"description":"Card not found"}},"summary":"Remove a saved card","tags":["Stripe Payments"]}},"/stripe/webhook":{"post":{"operationId":"handleWebhook","parameters":[{"name":"stripe-signature","required":true,"in":"header","description":"Stripe signature header","schema":{"type":"string"}}],"responses":{"200":{"description":"Webhook processed successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookResponseDto"}}}},"400":{"description":"Invalid signature or payload"}},"summary":"Stripe webhook endpoint","tags":["Stripe Payments"]}},"/tickets":{"get":{"operationId":"findMy","parameters":[],"responses":{"200":{"description":"List of user tickets","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TicketResponseDto"}}}}}},"security":[{"bearer":[]}],"summary":"Get my tickets (customer)","tags":["Tickets"]}},"/tickets/unread-count":{"get":{"operationId":"getUnreadCount","parameters":[],"responses":{"200":{"description":"Unread support replies count"}},"security":[{"bearer":[]}],"summary":"Get count of unread support replies (customer)","tags":["Tickets"]}},"/tickets/mark-all-read":{"post":{"operationId":"markAllAsRead","parameters":[],"responses":{"200":{"description":"All tickets marked as read"}},"security":[{"bearer":[]}],"summary":"Mark all tickets as read (customer)","tags":["Tickets"]}},"/tickets/{id}/replies":{"post":{"operationId":"addReply","parameters":[{"name":"id","required":true,"in":"path","description":"Ticket ID","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateReplyDto"}}}},"responses":{"201":{"description":"Reply added"}},"security":[{"bearer":[]}],"summary":"Add reply to ticket (customer)","tags":["Tickets"]}},"/tickets/{id}/close":{"patch":{"operationId":"close","parameters":[{"name":"id","required":true,"in":"path","description":"Ticket ID","schema":{"type":"string"}}],"responses":{"200":{"description":"Ticket closed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TicketResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Close my ticket (customer)","tags":["Tickets"]}},"/inbound-emails/webhook/resend":{"post":{"description":"Receives incoming emails from Resend and stores them for bot access","operationId":"handleResendWebhook","parameters":[{"name":"svix-id","required":true,"in":"header","schema":{"type":"string"}},{"name":"svix-timestamp","required":true,"in":"header","schema":{"type":"string"}},{"name":"svix-signature","required":true,"in":"header","schema":{"type":"string"}}],"responses":{"200":{"description":"Email received and processed"}},"security":[{"webhook-signature":[]}],"summary":"Resend inbound email webhook (PUBLIC)","tags":["Inbound Emails"]}},"/inbound-emails/webhook/mailersend":{"post":{"description":"Receives incoming emails from MailerSend and stores them for OpenClaw bot access","operationId":"handleMailerSendWebhook","parameters":[{"name":"x-mailersend-signature","required":true,"in":"header","schema":{"type":"string"}}],"responses":{"200":{"description":"Email received and processed"}},"security":[{"webhook-signature":[]}],"summary":"MailerSend inbound email webhook for proxies.sx (PUBLIC)","tags":["Inbound Emails"]}},"/inbound-emails/inbox/unread-count":{"get":{"operationId":"getUnreadCount","parameters":[],"responses":{"200":{"description":"Unread count"}},"security":[{"bearer":[]}],"summary":"Get unread email count","tags":["Inbound Emails"]}},"/internal/emails/inbox":{"get":{"description":"Get paginated list of inbound emails for Maya bot","operationId":"listInbox","parameters":[{"name":"limit","required":false,"in":"query","schema":{"example":10,"type":"number"}},{"name":"skip","required":false,"in":"query","schema":{"example":0,"type":"number"}},{"name":"isRead","required":false,"in":"query","schema":{"type":"boolean"}}],"responses":{"200":{"description":"List of inbound emails"}},"security":[{"internal-api-key":[]}],"summary":"List inbound emails (Internal)","tags":["Internal Email API"]}},"/internal/emails/inbox/{id}":{"get":{"description":"Get full email details including body by ID","operationId":"getInboxEmail","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"Email details"},"404":{"description":"Email not found"}},"security":[{"internal-api-key":[]}],"summary":"Get inbound email by ID (Internal)","tags":["Internal Email API"]}},"/internal/emails/sent":{"get":{"description":"Get paginated list of sent emails","operationId":"listSent","parameters":[{"name":"limit","required":false,"in":"query","schema":{"example":10,"type":"number"}},{"name":"skip","required":false,"in":"query","schema":{"example":0,"type":"number"}},{"name":"status","required":false,"in":"query","schema":{"enum":["sent","failed","bounced","delivered"],"type":"string"}}],"responses":{"200":{"description":"List of sent emails"}},"security":[{"internal-api-key":[]}],"summary":"List sent email history (Internal)","tags":["Internal Email API"]}},"/internal/emails/health":{"get":{"description":"Get MailerSend service health and domain status","operationId":"getHealth","parameters":[],"responses":{"200":{"description":"Health status"}},"security":[{"internal-api-key":[]}],"summary":"MailerSend health check (Internal)","tags":["Internal Email API"]}},"/coupons/validate":{"post":{"operationId":"validateCoupon","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidateCouponDto"}}}},"responses":{"200":{"description":"Validation result"}},"security":[{"bearer":[]}],"summary":"Validate a coupon code for current cart","tags":["Coupons"]}},"/coupons/my-redemptions":{"get":{"operationId":"getMyRedemptions","parameters":[{"name":"page","required":false,"in":"query","schema":{"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"type":"number"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"summary":"Get current user's redemption history","tags":["Coupons"]}},"/affiliate/apply":{"post":{"operationId":"applyForAffiliate","parameters":[],"responses":{"201":{"description":""}},"security":[{"JWT-auth":[]}],"summary":"Apply to become an affiliate","tags":["Affiliates"]}},"/affiliate/status":{"get":{"operationId":"getMyAffiliateStatus","parameters":[],"responses":{"200":{"description":""}},"security":[{"JWT-auth":[]}],"summary":"Get own affiliate status","tags":["Affiliates"]}},"/affiliate/referrals":{"get":{"operationId":"getMyReferrals","parameters":[{"name":"page","required":true,"in":"query","schema":{"type":"number"}},{"name":"limit","required":true,"in":"query","schema":{"type":"number"}}],"responses":{"200":{"description":""}},"security":[{"JWT-auth":[]}],"summary":"Get own referrals (anonymized)","tags":["Affiliates"]}},"/affiliate/commissions":{"get":{"operationId":"getMyCommissions","parameters":[{"name":"page","required":true,"in":"query","schema":{"type":"number"}},{"name":"limit","required":true,"in":"query","schema":{"type":"number"}}],"responses":{"200":{"description":""}},"security":[{"JWT-auth":[]}],"summary":"Get own commission history","tags":["Affiliates"]}},"/affiliate/payouts":{"get":{"operationId":"getMyPayouts","parameters":[{"name":"page","required":true,"in":"query","schema":{"type":"number"}},{"name":"limit","required":true,"in":"query","schema":{"type":"number"}}],"responses":{"200":{"description":""}},"security":[{"JWT-auth":[]}],"summary":"Get own payout history","tags":["Affiliates"]}},"/affiliate/payment-info":{"put":{"operationId":"updatePaymentInfo","parameters":[],"responses":{"200":{"description":""}},"security":[{"JWT-auth":[]}],"summary":"Update payment information","tags":["Affiliates"]}},"/affiliate/track-click":{"post":{"operationId":"trackClick","parameters":[],"responses":{"201":{"description":""}},"security":[{"JWT-auth":[]}],"summary":"Track affiliate link click (public)","tags":["Affiliates"]}},"/ref/{code}":{"get":{"operationId":"handleReferralRedirect","parameters":[{"name":"code","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"JWT-auth":[]}],"summary":"Redirect from affiliate link (public)","tags":["Affiliates"]}},"/telegram/link":{"post":{"operationId":"linkAccount","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"token":{"type":"string","description":"Telegram link session token"}},"required":["token"]}}}},"responses":{"200":{"description":"Account linked successfully"},"400":{"description":"Invalid or expired token"}},"security":[{"bearer":[]}],"summary":"Link Telegram account to user","tags":["Telegram"]}},"/telegram/status":{"get":{"operationId":"getLinkStatus","parameters":[],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"summary":"Check Telegram link status","tags":["Telegram"]}},"/telegram/notifications":{"post":{"operationId":"updateNotifications","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"enabled":{"type":"boolean"},"portExpiry":{"type":"boolean"},"lowBalance":{"type":"boolean"},"portStatus":{"type":"boolean"},"payments":{"type":"boolean"},"tickets":{"type":"boolean"}}}}}},"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"summary":"Update Telegram notification settings","tags":["Telegram"]}},"/admin/telegram/stats":{"get":{"operationId":"getStats","parameters":[],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"summary":"Get Telegram bot statistics","tags":["Admin - Telegram"]}},"/store/config/{subdomain}":{"get":{"operationId":"getPublicConfig","parameters":[{"name":"subdomain","required":true,"in":"path","description":"Store subdomain","schema":{"type":"string"}}],"responses":{"200":{"description":"Store configuration"}},"summary":"Get public store configuration (for frontend loading)","tags":["Farmer Store - Public"]}},"/store/check-subdomain/{subdomain}":{"get":{"operationId":"checkSubdomain","parameters":[{"name":"subdomain","required":true,"in":"path","description":"Subdomain to check","schema":{"type":"string"}}],"responses":{"200":{"description":"Availability status"}},"summary":"Check if subdomain is available","tags":["Farmer Store - Public"]}},"/email-campaigns/stats":{"get":{"operationId":"getStats","parameters":[],"responses":{"200":{"description":"Campaign statistics"}},"security":[{"bearer":[]}],"summary":"Get email campaign statistics","tags":["Email Campaigns"]}},"/x402/.well-known":{"get":{"operationId":"getWellKnown","parameters":[],"responses":{"200":{"description":"x402 server capabilities"}},"summary":"x402 protocol discovery endpoint","tags":["x402"]}},"/x402/pricing":{"get":{"operationId":"getPricing","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/X402PricingResponse"}}}}},"summary":"Get x402 pricing information","tags":["x402"]},"post":{"operationId":"postPricing","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/X402PricingResponse"}}}}},"summary":"Get x402 pricing information (POST)","tags":["x402"]}},"/x402/calculate":{"get":{"operationId":"calculateCost","parameters":[{"name":"tier","required":false,"in":"query","schema":{"enum":["shared","private"],"type":"string"}},{"name":"duration","required":true,"in":"query","schema":{"type":"number"}},{"name":"traffic","required":true,"in":"query","schema":{"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CalculateCostResponse"}}}}},"summary":"Calculate cost for proxy configuration","tags":["x402"]},"post":{"operationId":"postCalculateCost","parameters":[{"name":"tier","required":true,"in":"query","schema":{"type":"string"}},{"name":"duration","required":true,"in":"query","schema":{"type":"string"}},{"name":"traffic","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CalculateCostResponse"}}}}},"summary":"Calculate cost for proxy configuration (POST)","tags":["x402"]}},"/x402/proxy":{"get":{"operationId":"getProxy","parameters":[{"name":"country","required":true,"in":"query","description":"Country code or ID","schema":{"example":"US","type":"string"}},{"name":"city","required":false,"in":"query","description":"City code or ID","schema":{"example":"NYC","type":"string"}},{"name":"carrier","required":false,"in":"query","description":"Carrier code or ID","schema":{"example":"verizon","type":"string"}},{"name":"duration","required":true,"in":"query","description":"Duration in seconds","schema":{"minimum":3600,"maximum":2592000,"example":86400,"type":"number"}},{"name":"traffic","required":true,"in":"query","description":"Traffic in GB","schema":{"minimum":0.1,"example":1,"type":"number"}},{"name":"tier","required":false,"in":"query","description":"Tier: shared (default) or private","schema":{"enum":["shared","private"],"type":"string"}},{"name":"network","required":false,"in":"query","description":"Preferred network for payment (base or solana)","schema":{"enum":["base","solana"],"type":"string"}},{"name":"X-Agent-Name","in":"header","description":"Optional agent name for identification","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/X402ProxyResponse"}}}},"402":{"description":"Payment required"}},"summary":"Get a mobile proxy via GET (requires x402 payment)","tags":["x402"]},"post":{"operationId":"postProxy","parameters":[{"name":"country","required":true,"in":"query","description":"Country code (ISO 3166-1 alpha-2) or country MongoDB ID","schema":{"example":"US","type":"string"}},{"name":"city","required":false,"in":"query","description":"City code or MongoDB ID (optional)","schema":{"example":"NYC","type":"string"}},{"name":"carrier","required":false,"in":"query","description":"Carrier code or MongoDB ID (optional)","schema":{"example":"verizon","type":"string"}},{"name":"duration","required":true,"in":"query","description":"Duration in seconds (min: 3600, max: 2592000)","schema":{"minimum":3600,"maximum":2592000,"example":86400,"type":"number"}},{"name":"traffic","required":true,"in":"query","description":"Traffic allocation in GB (min: 0.1)","schema":{"minimum":0.1,"example":1,"type":"number"}},{"name":"tier","required":false,"in":"query","description":"Tier: shared (default) or private","schema":{"example":"shared","type":"string","enum":["shared","private"]}},{"name":"network","required":false,"in":"query","description":"Preferred network for payment (base or solana)","schema":{"example":"base","type":"string","enum":["base","solana"]}},{"name":"X-Agent-Name","in":"header","description":"Optional agent name for identification","required":false,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/X402ProxyRequestDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/X402ProxyResponse"}}}},"402":{"description":"Payment required"}},"summary":"Get a mobile proxy via POST (requires x402 payment)","tags":["x402"]}},"/x402/session/{id}":{"get":{"operationId":"getSession","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/X402SessionResponse"}}}}},"summary":"Get x402 session details","tags":["x402"]}},"/x402/sessions/wallet/{wallet}":{"get":{"operationId":"getSessionsByWallet","parameters":[{"name":"wallet","required":true,"in":"path","schema":{"type":"string"}},{"name":"status","required":false,"in":"query","schema":{"enum":["active","expired","all"],"type":"string"}}],"responses":{"200":{"description":""}},"summary":"List sessions by wallet address (public)","tags":["x402"]}},"/x402/sessions/{id}/status":{"get":{"operationId":"getSessionStatusById","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"summary":"Get session status by ID (public)","tags":["x402"]}},"/x402/session/tx/{txHash}":{"get":{"operationId":"getSessionByTx","parameters":[{"name":"txHash","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/X402SessionResponse"}}}}},"summary":"Get x402 session by transaction hash","tags":["x402"]}},"/x402/health":{"get":{"operationId":"healthCheck","parameters":[],"responses":{"200":{"description":""}},"summary":"Check x402 service health","tags":["x402"]},"post":{"operationId":"postHealthCheck","parameters":[],"responses":{"201":{"description":""}},"summary":"Check x402 service health (POST)","tags":["x402"]}},"/x402/info":{"get":{"operationId":"getMasterInfo","parameters":[],"responses":{"200":{"description":"Complete x402 service info including pricing, networks, countries, stats, services, benchmarks, and MCP server details"}},"summary":"Get complete x402 service information (master endpoint - canonical source of truth)","tags":["x402"]}},"/x402/verify":{"get":{"operationId":"getVerifications","parameters":[],"responses":{"200":{"description":"Verification results for all services"}},"summary":"Get service verification results (public, no auth)","tags":["x402"]}},"/x402/verify/{serviceId}":{"get":{"operationId":"getServiceVerification","parameters":[{"name":"serviceId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"Service verification result"}},"summary":"Get verification result for a specific service","tags":["x402"]}},"/x402/status":{"get":{"operationId":"getStatus","parameters":[],"responses":{"200":{"description":"Service status with uptime percentages and recent incidents"}},"summary":"Get service status and uptime (public, no auth)","tags":["x402"]}},"/x402/countries":{"get":{"operationId":"getAvailableCountries","parameters":[{"name":"tier","required":false,"in":"query","description":"Filter by tier","schema":{"enum":["shared","private"],"type":"string"}}],"responses":{"200":{"description":"List of countries with available devices"}},"summary":"Get available countries with device counts (no auth required)","tags":["x402"]}},"/x402/manage/session":{"get":{"operationId":"getSessionByToken","parameters":[{"name":"x-session-token","required":true,"in":"header","schema":{"type":"string"}},{"name":"X-Session-Token","in":"header","description":"Session token from purchase response","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/X402SessionResponse"}}}},"401":{"description":"Invalid or missing session token"}},"summary":"Get session details (requires session token)","tags":["x402"]}},"/x402/manage/ports/{portId}/status":{"get":{"operationId":"getPortStatusByToken","parameters":[{"name":"portId","required":true,"in":"path","schema":{"type":"string"}},{"name":"x-session-token","required":true,"in":"header","schema":{"type":"string"}},{"name":"X-Session-Token","in":"header","description":"Session token from purchase response","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":""},"401":{"description":"Invalid session token"},"404":{"description":"Port not found or not owned by session"}},"summary":"Get port status (requires session token)","tags":["x402"]}},"/x402/manage/ports":{"get":{"operationId":"listSessionPortsByToken","parameters":[{"name":"x-session-token","required":true,"in":"header","schema":{"type":"string"}},{"name":"X-Session-Token","in":"header","description":"Session token from purchase response","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":""},"401":{"description":"Invalid session token"}},"summary":"List all ports in session (requires session token)","tags":["x402"]}},"/x402/manage/ports/recreate":{"post":{"operationId":"recreateSessionPort","parameters":[{"name":"x-session-token","required":true,"in":"header","schema":{"type":"string"}},{"name":"X-Session-Token","in":"header","description":"Session token from purchase response","required":true,"schema":{"type":"string"}}],"responses":{"201":{"description":"Port recreated successfully"},"400":{"description":"Session has no remaining credit or traffic"},"401":{"description":"Invalid session token"}},"summary":"Recreate port for session with remaining credit (requires session token)","tags":["x402"]}},"/x402/manage/session/credit":{"get":{"operationId":"getSessionCredit","parameters":[{"name":"x-session-token","required":true,"in":"header","schema":{"type":"string"}},{"name":"X-Session-Token","in":"header","description":"Session token from purchase response","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":""},"401":{"description":"Invalid session token"}},"summary":"Check session remaining credit for port recreation (requires session token)","tags":["x402"]}},"/x402/manage/ports/replace":{"post":{"operationId":"replacePort","parameters":[{"name":"x-session-token","required":true,"in":"header","schema":{"type":"string"}},{"name":"X-Session-Token","in":"header","description":"Session token from purchase response","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/X402ReplacePortDto"}}}},"responses":{"200":{"description":"Port replaced successfully"},"400":{"description":"Port is online, max replacements reached, or no alternative devices"},"401":{"description":"Invalid session token"}},"summary":"Replace offline port with new one (free, max 3 replacements, requires session token)","tags":["x402"]}},"/x402/manage/session/topup/calculate":{"get":{"operationId":"calculateTopupCost","parameters":[{"name":"x-session-token","required":true,"in":"header","schema":{"type":"string"}},{"name":"addTrafficGB","required":false,"in":"query","description":"Additional traffic in GB","schema":{"type":"number"}},{"name":"addDurationSeconds","required":false,"in":"query","description":"Additional duration in seconds","schema":{"type":"number"}},{"name":"X-Session-Token","in":"header","description":"Session token from purchase response","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Cost calculation"}},"summary":"Calculate top-up cost for a session (requires session token)","tags":["x402"]}},"/x402/manage/session/topup":{"post":{"operationId":"topupSession","parameters":[{"name":"x-session-token","required":true,"in":"header","schema":{"type":"string"}},{"name":"payment-signature","required":true,"in":"header","schema":{"type":"string"}},{"name":"Payment-Signature","in":"header","description":"Blockchain tx hash (Solana signature or Base tx hash)","required":true,"schema":{"type":"string"}},{"name":"X-Session-Token","in":"header","description":"Session token from purchase response","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/X402TopupDto"}}}},"responses":{"200":{"description":"Session topped up successfully"},"400":{"description":"Invalid parameters or insufficient payment"},"401":{"description":"Invalid session token"}},"summary":"Top up session with additional traffic/duration (requires session token + payment)","tags":["x402"]}},"/x402/agents":{"post":{"operationId":"registerAgent","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegisterAgentDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/X402AgentResponse"}}}},"409":{"description":"Wallet already registered"}},"summary":"Register a new agent","tags":["x402"]}},"/x402/agents/{wallet}":{"get":{"operationId":"getAgent","parameters":[{"name":"wallet","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/X402AgentResponse"}}}},"404":{"description":"Agent not found"}},"summary":"Get agent by wallet address","tags":["x402"]}},"/reseller/docs/llm":{"get":{"operationId":"getLlmDocs","parameters":[],"responses":{"200":{"description":"Returns plain text API documentation optimized for LLMs"}},"summary":"Get LLM-friendly API documentation","tags":["Reseller - Documentation"]}},"/reseller/docs/openapi":{"get":{"operationId":"getOpenApi","parameters":[],"responses":{"200":{"description":"Returns OpenAPI 3.0 JSON specification"}},"summary":"Get OpenAPI specification","tags":["Reseller - Documentation"]}},"/reseller/customers/tiers/info":{"get":{"description":"Returns all tier levels with their GB requirements and slot allocations. Use this to display tier progression to customers.","operationId":"getAllTiers","parameters":[],"responses":{"200":{"description":"Tier information retrieved","content":{"application/json":{"schema":{"example":{"basePrices":{"shared":4,"private":8},"volumeDiscounts":[{"minGB":1,"maxGB":24,"discountPercent":0},{"minGB":25,"maxGB":49,"discountPercent":10},{"minGB":50,"maxGB":99,"discountPercent":20},{"minGB":100,"maxGB":249,"discountPercent":30},{"minGB":250,"maxGB":null,"discountPercent":40}],"slotTiers":[{"name":"Starter","minGB":0,"sharedSlots":5,"privateSlots":1},{"name":"Bronze","minGB":25,"sharedSlots":10,"privateSlots":2},{"name":"Silver","minGB":50,"sharedSlots":20,"privateSlots":4},{"name":"Gold","minGB":100,"sharedSlots":35,"privateSlots":7},{"name":"Platinum","minGB":250,"sharedSlots":50,"privateSlots":10},{"name":"Enterprise","minGB":500,"sharedSlots":80,"privateSlots":15}]}}}}}},"security":[{"JWT-auth":[]}],"summary":"Get all available slot tiers","tags":["Reseller - Customers"]}},"/reseller/customers/by-external-id/{externalId}":{"get":{"operationId":"findByExternalId","parameters":[{"name":"externalId","required":true,"in":"path","description":"External customer ID","schema":{"type":"string"}}],"responses":{"200":{"description":"Customer retrieved"},"404":{"description":"Customer not found"}},"security":[{"JWT-auth":[]}],"summary":"Get customer by external ID","tags":["Reseller - Customers"]}},"/reseller/customers/{id}/suspend":{"post":{"operationId":"suspend","parameters":[{"name":"id","required":true,"in":"path","description":"Customer ID","schema":{"example":"507f1f77bcf86cd799439011","type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuspendCustomerDto"},"examples":{"withReason":{"value":{"reason":"Non-payment"},"summary":"With reason"},"noReason":{"value":{},"summary":"Without reason"}}}}},"responses":{"200":{"description":"Customer suspended successfully","content":{"application/json":{"schema":{"example":{"_id":"507f1f77bcf86cd799439011","status":"suspended"}}}}},"400":{"description":"Customer already suspended"},"404":{"description":"Customer not found"}},"security":[{"JWT-auth":[]}],"summary":"Suspend a sub-account","tags":["Reseller - Customers"]}},"/reseller/customers/{id}/unsuspend":{"post":{"operationId":"unsuspend","parameters":[{"name":"id","required":true,"in":"path","description":"Customer ID","schema":{"example":"507f1f77bcf86cd799439011","type":"string"}}],"responses":{"200":{"description":"Customer reactivated successfully","content":{"application/json":{"schema":{"example":{"_id":"507f1f77bcf86cd799439011","status":"active"}}}}},"400":{"description":"Customer is not suspended"},"404":{"description":"Customer not found"}},"security":[{"JWT-auth":[]}],"summary":"Reactivate a suspended sub-account","tags":["Reseller - Customers"]}},"/reseller/customers/{id}/topup":{"post":{"description":"Adds credit to customer internal balance. This is for tracking purposes - actual billing is handled separately.","operationId":"topup","parameters":[{"name":"id","required":true,"in":"path","description":"Customer ID","schema":{"example":"507f1f77bcf86cd799439011","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TopupCustomerDto"},"examples":{"simple":{"value":{"amount":100},"summary":"Simple topup"},"withReference":{"value":{"amount":500,"description":"Monthly credit allocation","referenceId":"INV-2026-001"},"summary":"Topup with reference"}}}}},"responses":{"200":{"description":"Balance added successfully","content":{"application/json":{"schema":{"example":{"_id":"507f1f77bcf86cd799439011","balance":600,"totalSpent":0}}}}},"404":{"description":"Customer not found"}},"security":[{"JWT-auth":[]}],"summary":"Add balance to a sub-account","tags":["Reseller - Customers"]}},"/reseller/customers/{id}/quota":{"put":{"description":"Sets the absolute quota values for port slots and traffic. Replaces existing values.","operationId":"allocateQuota","parameters":[{"name":"id","required":true,"in":"path","description":"Customer ID","schema":{"example":"507f1f77bcf86cd799439011","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AllocateQuotaDto"},"examples":{"portSlots":{"value":{"portSlots":20},"summary":"Set port slots only"},"both":{"value":{"portSlots":50,"trafficGB":500},"summary":"Set both quotas"}}}}},"responses":{"200":{"description":"Quota updated successfully","content":{"application/json":{"schema":{"example":{"_id":"507f1f77bcf86cd799439011","allocatedPortSlots":50,"allocatedTrafficGB":500}}}}},"400":{"description":"Cannot reduce quota below usage"},"404":{"description":"Customer not found"}},"security":[{"JWT-auth":[]}],"summary":"Set quota allocation for a sub-account","tags":["Reseller - Customers"]},"patch":{"description":"Incrementally adjusts quota values. Use positive numbers to add, negative to reduce.","operationId":"adjustQuota","parameters":[{"name":"id","required":true,"in":"path","description":"Customer ID","schema":{"example":"507f1f77bcf86cd799439011","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdjustQuotaDto"},"examples":{"increase":{"value":{"portSlotsDelta":5,"reason":"Upgrade to premium"},"summary":"Add 5 slots"},"decrease":{"value":{"portSlotsDelta":-2,"reason":"Downgrade"},"summary":"Remove 2 slots"}}}}},"responses":{"200":{"description":"Quota adjusted successfully","content":{"application/json":{"schema":{"example":{"_id":"507f1f77bcf86cd799439011","allocatedPortSlots":25,"usedPortSlots":10}}}}},"400":{"description":"Quota adjustment would result in negative or below-usage quota"},"404":{"description":"Customer not found"}},"security":[{"JWT-auth":[]}],"summary":"Adjust quota for a sub-account","tags":["Reseller - Customers"]}},"/reseller/customers/{id}/usage":{"get":{"operationId":"getUsage","parameters":[{"name":"id","required":true,"in":"path","description":"Customer ID","schema":{"type":"string"}}],"responses":{"200":{"description":"Usage stats retrieved"},"404":{"description":"Customer not found"}},"security":[{"JWT-auth":[]}],"summary":"Get usage statistics for a sub-account","tags":["Reseller - Customers"]}},"/reseller/customers/{id}/quota-status":{"get":{"operationId":"getQuotaStatus","parameters":[{"name":"id","required":true,"in":"path","description":"Customer ID","schema":{"type":"string"}}],"responses":{"200":{"description":"Quota status retrieved"},"404":{"description":"Customer not found"}},"security":[{"JWT-auth":[]}],"summary":"Get quota status for a sub-account","tags":["Reseller - Customers"]}},"/reseller/customers/{id}/tier-info":{"get":{"description":"Returns the customer's current tier, next tier, and progress toward tier upgrades based on cumulative GB purchases.","operationId":"getTierInfo","parameters":[{"name":"id","required":true,"in":"path","description":"Customer ID","schema":{"example":"507f1f77bcf86cd799439011","type":"string"}}],"responses":{"200":{"description":"Tier information retrieved","content":{"application/json":{"schema":{"example":{"currentTier":{"name":"Bronze","minGB":25,"sharedSlots":10,"privateSlots":2},"nextTier":{"name":"Silver","minGB":50,"sharedSlots":20,"privateSlots":4},"cumulativeGB":35,"gbToNextTier":15,"sharedSlotLimit":10,"privateSlotLimit":2,"effectiveLimits":{"sharedSlots":10,"privateSlots":2,"totalSlots":12,"isManualOverride":false}}}}}},"404":{"description":"Customer not found"}},"security":[{"JWT-auth":[]}],"summary":"Get customer tier information","tags":["Reseller - Customers"]}},"/reseller/customers/{id}/refund":{"post":{"description":"Refunds an amount from customer balance BACK to your reseller balance. Use this for cancellations or corrections.","operationId":"refundBalance","parameters":[{"name":"id","required":true,"in":"path","description":"Customer ID","schema":{"example":"507f1f77bcf86cd799439011","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RefundBalanceDto"},"examples":{"cancellation":{"value":{"amount":30,"reason":"Port cancellation - 15 days unused","referenceId":"REF-2026-001"},"summary":"Port cancellation refund"},"correction":{"value":{"amount":10,"reason":"Billing correction"},"summary":"Billing correction"}}}}},"responses":{"200":{"description":"Balance refunded to reseller successfully","content":{"application/json":{"schema":{"example":{"success":true,"message":"Refunded $30.00 from customer to reseller balance","customer":{"_id":"...","balance":70,"totalSpent":30},"transaction":{"_id":"...","type":"refund","amount":-30,"resellerBalanceAffected":true}}}}}},"400":{"description":"Insufficient customer balance for refund"},"404":{"description":"Customer not found"}},"security":[{"JWT-auth":[]}],"summary":"Refund customer balance back to reseller","tags":["Reseller - Customers"]}},"/reseller/customers/{id}/adjust-balance":{"post":{"description":"Adjusts customer balance without affecting reseller balance. Use for goodwill credits, corrections, or manual adjustments. Positive = add, negative = deduct.","operationId":"adjustBalance","parameters":[{"name":"id","required":true,"in":"path","description":"Customer ID","schema":{"example":"507f1f77bcf86cd799439011","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdjustBalanceDto"},"examples":{"goodwillCredit":{"value":{"amount":20,"reason":"Goodwill credit for service disruption","referenceId":"TKT-2026-001"},"summary":"Add goodwill credit"},"correction":{"value":{"amount":-5,"reason":"Billing correction - overcharge","referenceId":"ADJ-2026-001"},"summary":"Deduct for correction"}}}}},"responses":{"200":{"description":"Balance adjusted successfully","content":{"application/json":{"schema":{"example":{"success":true,"customer":{"_id":"...","balance":120,"totalTopUp":120},"transaction":{"_id":"...","type":"adjust","amount":20,"resellerBalanceAffected":false}}}}}},"400":{"description":"Insufficient balance for negative adjustment"},"404":{"description":"Customer not found"}},"security":[{"JWT-auth":[]}],"summary":"Adjust customer balance (no reseller impact)","tags":["Reseller - Customers"]}},"/reseller/customers/{id}/transactions":{"get":{"description":"Returns all balance transactions (topups, deductions, refunds, adjustments) for a customer.","operationId":"getTransactions","parameters":[{"name":"id","required":true,"in":"path","description":"Customer ID","schema":{"example":"507f1f77bcf86cd799439011","type":"string"}},{"name":"type","required":false,"in":"query","description":"Filter by transaction type","schema":{"enum":["topup","deduct","refund","adjust","port_charge"],"type":"string"}},{"name":"startDate","required":false,"in":"query","description":"Start date (ISO format)","schema":{"type":"string"}},{"name":"endDate","required":false,"in":"query","description":"End date (ISO format)","schema":{"type":"string"}},{"name":"skip","required":false,"in":"query","schema":{"default":0,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"default":20,"type":"number"}}],"responses":{"200":{"description":"Transactions retrieved successfully","content":{"application/json":{"schema":{"example":{"transactions":[{"_id":"...","type":"topup","amount":100,"balanceBefore":0,"balanceAfter":100,"reason":"Initial topup","createdAt":"2026-01-19T12:00:00Z"},{"_id":"...","type":"deduct","amount":-60,"balanceBefore":100,"balanceAfter":40,"reason":"Port purchase","createdAt":"2026-01-19T14:00:00Z"}],"total":2,"skip":0,"limit":20}}}}},"404":{"description":"Customer not found"}},"security":[{"JWT-auth":[]}],"summary":"Get customer balance transaction history","tags":["Reseller - Customers"]}},"/reseller/pricebook":{"get":{"operationId":"get","parameters":[],"responses":{"200":{"description":"Pricebook retrieved"}},"security":[{"JWT-auth":[]}],"summary":"Get current pricing rules","tags":["Reseller - Pricing"]}},"/reseller/pricebook/calculate":{"post":{"description":"Preview the price calculation for a port purchase using your pricebook rules.","operationId":"calculatePrice","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CalculatePriceDto"},"examples":{"basic":{"value":{"basePrice":2,"days":30},"summary":"30-day port at $2/day base"},"withCountry":{"value":{"basePrice":2,"days":7,"countryId":"507f1f77bcf86cd799439011"},"summary":"7-day port with country override"}}}}},"responses":{"200":{"description":"Price calculated","content":{"application/json":{"schema":{"example":{"basePrice":60,"resellerPrice":75,"marginAmount":15,"marginPercent":25,"appliedRules":["Margin: +25%"]}}}}}},"security":[{"JWT-auth":[]}],"summary":"Calculate price for a purchase","tags":["Reseller - Pricing"]}},"/reseller/pricebook/country-override":{"post":{"description":"Set custom pricing rules for a specific country, overriding the default pricebook.","operationId":"addCountryOverride","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CountryOverrideDto"},"examples":{"premium":{"value":{"countryId":"507f1f77bcf86cd799439011","marginPercent":40},"summary":"Premium country with 40% margin"},"fixed":{"value":{"countryId":"507f1f77bcf86cd799439011","fixedPricePerDay":5},"summary":"Fixed price per day"}}}}},"responses":{"200":{"description":"Country override added","content":{"application/json":{"schema":{"example":{"success":true,"countryOverrides":1}}}}}},"security":[{"JWT-auth":[]}],"summary":"Add or update country-specific pricing","tags":["Reseller - Pricing"]}},"/reseller/pricebook/country-override/{countryId}":{"delete":{"operationId":"removeCountryOverride","parameters":[{"name":"countryId","required":true,"in":"path","description":"Country ID","schema":{"example":"507f1f77bcf86cd799439011","type":"string"}}],"responses":{"200":{"description":"Country override removed","content":{"application/json":{"schema":{"example":{"success":true,"countryOverrides":0}}}}}},"security":[{"JWT-auth":[]}],"summary":"Remove country-specific pricing","tags":["Reseller - Pricing"]}},"/reseller/webhooks/event-types":{"get":{"operationId":"getEventTypes","parameters":[],"responses":{"200":{"description":"Event types retrieved"}},"security":[{"JWT-auth":[]}],"summary":"Get available webhook event types","tags":["Reseller - Webhooks"]}},"/reseller/webhooks/{id}/test":{"post":{"description":"Sends a test payload to verify webhook configuration and connectivity.","operationId":"test","parameters":[{"name":"id","required":true,"in":"path","description":"Webhook ID","schema":{"example":"507f1f77bcf86cd799439011","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestWebhookDto"},"examples":{"portCreated":{"value":{"eventType":"port.created"},"summary":"Test port.created event"},"customerSuspended":{"value":{"eventType":"customer.suspended"},"summary":"Test customer.suspended event"}}}}},"responses":{"200":{"description":"Test event sent","content":{"application/json":{"schema":{"example":{"success":true,"statusCode":200,"responseTime":145,"deliveryId":"507f1f77bcf86cd799439012"}}}}},"404":{"description":"Webhook not found"}},"security":[{"JWT-auth":[]}],"summary":"Send a test event to webhook","tags":["Reseller - Webhooks"]}},"/reseller/webhooks/{id}/deliveries":{"get":{"operationId":"getDeliveries","parameters":[{"name":"id","required":true,"in":"path","description":"Webhook ID","schema":{"type":"string"}},{"name":"status","required":false,"in":"query","description":"Filter by delivery status","schema":{"type":"string","enum":["pending","success","failed","retrying"]}},{"name":"eventType","required":false,"in":"query","description":"Filter by event type","schema":{"type":"string","enum":["port.created","port.deleted","port.expiring","port.expired","port.rotated","port.suspended","port.unsuspended","customer.created","customer.updated","customer.suspended","customer.unsuspended","customer.tier_upgraded","customer.quota_warning","customer.quota_exceeded","traffic.threshold_50","traffic.threshold_80","traffic.threshold_100","balance.low","balance.topup","purchase.completed"]}},{"name":"skip","required":false,"in":"query","description":"Number of records to skip","schema":{"minimum":0,"default":0,"type":"number"}},{"name":"limit","required":false,"in":"query","description":"Number of records to return","schema":{"minimum":1,"default":20,"type":"number"}}],"responses":{"200":{"description":"Deliveries retrieved"},"404":{"description":"Webhook not found"}},"security":[{"JWT-auth":[]}],"summary":"Get delivery history for a webhook","tags":["Reseller - Webhooks"]}},"/reseller/analytics/revenue":{"get":{"operationId":"getRevenue","parameters":[{"name":"startDate","required":false,"in":"query","description":"Start date (ISO)","schema":{"type":"string"}},{"name":"endDate","required":false,"in":"query","description":"End date (ISO)","schema":{"type":"string"}}],"responses":{"200":{"description":"Revenue summary retrieved"}},"security":[{"JWT-auth":[]}],"summary":"Get revenue summary","tags":["Reseller - Analytics"]}},"/reseller/analytics/revenue/by-period":{"get":{"operationId":"getRevenueByPeriod","parameters":[{"name":"period","required":false,"in":"query","description":"Grouping period","schema":{"enum":["day","week","month"],"type":"string"}},{"name":"startDate","required":false,"in":"query","description":"Start date (ISO)","schema":{"type":"string"}},{"name":"endDate","required":false,"in":"query","description":"End date (ISO)","schema":{"type":"string"}}],"responses":{"200":{"description":"Revenue by period retrieved"}},"security":[{"JWT-auth":[]}],"summary":"Get revenue breakdown by time period","tags":["Reseller - Analytics"]}},"/reseller/analytics/revenue/by-customer":{"get":{"operationId":"getRevenueByCustomer","parameters":[{"name":"startDate","required":false,"in":"query","description":"Start date (ISO)","schema":{"type":"string"}},{"name":"endDate","required":false,"in":"query","description":"End date (ISO)","schema":{"type":"string"}},{"name":"limit","required":false,"in":"query","description":"Number of customers","schema":{"type":"number"}}],"responses":{"200":{"description":"Revenue by customer retrieved"}},"security":[{"JWT-auth":[]}],"summary":"Get revenue breakdown by customer","tags":["Reseller - Analytics"]}},"/reseller/analytics/commissions":{"get":{"operationId":"getCommissions","parameters":[{"name":"customerId","required":false,"in":"query","description":"Filter by customer","schema":{"type":"string"}},{"name":"type","required":false,"in":"query","description":"Filter by type","schema":{"enum":["port_purchase","traffic_purchase","renewal","topup"],"type":"string"}},{"name":"startDate","required":false,"in":"query","description":"Start date (ISO)","schema":{"type":"string"}},{"name":"endDate","required":false,"in":"query","description":"End date (ISO)","schema":{"type":"string"}},{"name":"skip","required":false,"in":"query","schema":{"default":0,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"default":20,"type":"number"}}],"responses":{"200":{"description":"Commissions retrieved"}},"security":[{"JWT-auth":[]}],"summary":"List commission entries","tags":["Reseller - Analytics"]}},"/reseller/ports":{"post":{"description":"Creates a new proxy port for a reseller customer.\n\n**Flow:**\n1. Verify customer belongs to reseller\n2. Check customer quota and permissions\n3. Check reseller has sufficient balance\n4. Calculate price (wholesale cost to reseller)\n5. Create port on ProxySmart/iProxy\n6. Update port with reseller ownership\n7. Deduct from reseller balance\n8. Increment customer usedPortSlots\n9. Record commission for analytics\n10. Emit webhook notification","operationId":"createPortForCustomer","parameters":[],"requestBody":{"required":true,"description":"Port creation parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatePortForCustomerDto"},"examples":{"sharedPort":{"value":{"customerId":"507f1f77bcf86cd799439011","countryId":"507f1f77bcf86cd799439012","days":30,"isPrivate":false},"summary":"30-day shared port","description":"Creates a shared port (multiple ports per modem) for 30 days"},"privatePort":{"value":{"customerId":"507f1f77bcf86cd799439011","countryId":"507f1f77bcf86cd799439012","cityId":"507f1f77bcf86cd799439013","carrierId":"507f1f77bcf86cd799439014","days":7,"isPrivate":true,"exclusive":true},"summary":"7-day private dedicated port","description":"Creates a private dedicated port (1 port per modem) with specific location"},"minimalPort":{"value":{"customerId":"507f1f77bcf86cd799439011","countryId":"507f1f77bcf86cd799439012"},"summary":"Minimal port (defaults)","description":"Creates a port with defaults: 30 days, shared, no city/carrier filter"}}}}},"responses":{"201":{"description":"Port created successfully","content":{"application/json":{"schema":{"example":{"port":{"_id":"507f1f77bcf86cd799439015","displayName":"Port-ABC123","name":"psx_abc123_xyz789","httpPort":30001,"socksPort":30002,"proxyLogin":"user_abc123","proxyPassword":"secure_pass_xyz","expiresAt":"2026-02-19T12:00:00.000Z","status":"active","suspended":false,"resellerId":"507f1f77bcf86cd799439016","resellerCustomerId":"507f1f77bcf86cd799439011","deviceId":{"_id":"507f1f77bcf86cd799439017","imei":"123456789012345","countryId":"507f1f77bcf86cd799439012","carrierId":"507f1f77bcf86cd799439014"}},"pricing":{"costToReseller":60,"resellerPrice":75,"margin":15}}}}}},"400":{"description":"Invalid input or quota exceeded"},"402":{"description":"Insufficient reseller balance"},"403":{"description":"Customer suspended or not allowed to create ports"}},"security":[{"JWT-auth":[]}],"summary":"Create a port for a customer","tags":["Reseller - Ports"]},"get":{"operationId":"listAllPorts","parameters":[{"name":"customerId","required":false,"in":"query","description":"Filter by customer ID","schema":{"type":"string"}},{"name":"countryId","required":false,"in":"query","description":"Filter by country ID","schema":{"type":"string"}},{"name":"status","required":false,"in":"query","description":"Filter by status","schema":{"type":"string","enum":["active","expired","suspended"]}},{"name":"skip","required":false,"in":"query","description":"Number of records to skip","schema":{"minimum":0,"default":0,"type":"number"}},{"name":"limit","required":false,"in":"query","description":"Number of records to return","schema":{"minimum":1,"default":20,"type":"number"}}],"responses":{"200":{"description":"Ports retrieved"}},"security":[{"JWT-auth":[]}],"summary":"List all ports across all customers","tags":["Reseller - Ports"]}},"/reseller/ports/customer/{customerId}":{"get":{"operationId":"listCustomerPorts","parameters":[{"name":"customerId","required":true,"in":"path","description":"Customer ID","schema":{"type":"string"}},{"name":"countryId","required":false,"in":"query","description":"Filter by country ID","schema":{"type":"string"}},{"name":"status","required":false,"in":"query","description":"Filter by status","schema":{"type":"string","enum":["active","expired","suspended"]}},{"name":"skip","required":false,"in":"query","description":"Number of records to skip","schema":{"minimum":0,"default":0,"type":"number"}},{"name":"limit","required":false,"in":"query","description":"Number of records to return","schema":{"minimum":1,"default":20,"type":"number"}}],"responses":{"200":{"description":"Customer ports retrieved"}},"security":[{"JWT-auth":[]}],"summary":"List ports for a specific customer","tags":["Reseller - Ports"]}},"/reseller/ports/expiring":{"get":{"operationId":"listExpiringPorts","parameters":[{"name":"hours","required":false,"in":"query","description":"Hours until expiration (default: 24)","schema":{"type":"number"}}],"responses":{"200":{"description":"Expiring ports retrieved"}},"security":[{"JWT-auth":[]}],"summary":"List ports expiring within specified hours","tags":["Reseller - Ports"]}},"/reseller/ports/summary":{"get":{"operationId":"getPortSummary","parameters":[],"responses":{"200":{"description":"Port summary retrieved"}},"security":[{"JWT-auth":[]}],"summary":"Get port summary statistics","tags":["Reseller - Ports"]}},"/reseller/ports/{portId}":{"get":{"operationId":"getPort","parameters":[{"name":"portId","required":true,"in":"path","description":"Port ID","schema":{"type":"string"}}],"responses":{"200":{"description":"Port retrieved"},"404":{"description":"Port not found"}},"security":[{"JWT-auth":[]}],"summary":"Get port details","tags":["Reseller - Ports"]},"delete":{"description":"Soft deletes a port and releases the customer quota slot. The port is marked as deleted but not permanently removed.","operationId":"deletePort","parameters":[{"name":"portId","required":true,"in":"path","description":"Port ID to delete","schema":{"example":"507f1f77bcf86cd799439011","type":"string"}}],"responses":{"200":{"description":"Port deleted successfully","content":{"application/json":{"schema":{"example":{"success":true,"message":"Port deleted successfully"}}}}},"400":{"description":"Port not found"}},"security":[{"JWT-auth":[]}],"summary":"Delete a port (soft delete)","tags":["Reseller - Ports"]}},"/reseller/ports/check-quota":{"post":{"operationId":"checkQuota","parameters":[],"requestBody":{"required":true,"description":"Customer ID to check quota for","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckQuotaDto"},"examples":{"example":{"value":{"customerId":"507f1f77bcf86cd799439011"},"summary":"Check quota for a customer"}}}}},"responses":{"200":{"description":"Quota status retrieved","content":{"application/json":{"schema":{"example":{"canCreate":true,"reason":"Quota available","quotaStatus":{"allocatedPortSlots":10,"usedPortSlots":3,"availablePortSlots":7,"canCreatePorts":true}}}}}}},"security":[{"JWT-auth":[]}],"summary":"Check if customer has available quota for port creation","tags":["Reseller - Ports"]}},"/reseller/ports/calculate-price":{"post":{"operationId":"calculatePrice","parameters":[],"requestBody":{"required":true,"description":"Parameters for price calculation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CalculatePortPriceDto"},"examples":{"sharedPort":{"value":{"customerId":"507f1f77bcf86cd799439011","days":30,"isPrivate":false},"summary":"30-day shared port"},"privatePort":{"value":{"customerId":"507f1f77bcf86cd799439011","days":7,"isPrivate":true,"countryId":"507f1f77bcf86cd799439012"},"summary":"7-day private port with country"}}}}},"responses":{"200":{"description":"Price calculated","content":{"application/json":{"schema":{"example":{"basePrice":60,"resellerPrice":75,"marginAmount":15,"marginPercent":25,"appliedRules":["Margin: +25%","30 days"]}}}}}},"security":[{"JWT-auth":[]}],"summary":"Calculate price for port purchase","tags":["Reseller - Ports"]}},"/reseller/ports/{portId}/extend":{"post":{"operationId":"extendPortTime","parameters":[{"name":"portId","required":true,"in":"path","description":"Port ID to extend","schema":{"example":"507f1f77bcf86cd799439011","type":"string"}}],"requestBody":{"required":true,"description":"Number of days to extend the port","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExtendPortDto"},"examples":{"week":{"value":{"days":7},"summary":"Extend by 1 week"},"month":{"value":{"days":30},"summary":"Extend by 1 month"}}}}},"responses":{"200":{"description":"Port time extended","content":{"application/json":{"schema":{"example":{"success":true,"message":"Port time extended by 168 hours","portId":"507f1f77bcf86cd799439011","hoursAdded":168,"newExpiresAt":"2026-02-19T12:00:00.000Z"}}}}},"404":{"description":"Port not found"}},"security":[{"JWT-auth":[]}],"summary":"Extend port expiration time","tags":["Reseller - Ports"]}},"/reseller/ports/{portId}/rotate":{"post":{"description":"Switches the port to a different modem while preserving port name, credentials, and expiration time. Respects 5-minute cooldown between rotations.","operationId":"rotatePort","parameters":[{"name":"portId","required":true,"in":"path","description":"Port ID","schema":{"example":"507f1f77bcf86cd799439011","type":"string"}}],"responses":{"200":{"description":"Port rotated successfully","content":{"application/json":{"schema":{"example":{"success":true,"message":"Port rotated successfully","portId":"507f1f77bcf86cd799439011","newDeviceId":"507f1f77bcf86cd799439018"}}}}},"400":{"description":"Port not found or rotation cooldown active"}},"security":[{"JWT-auth":[]}],"summary":"Rotate port to a new device","tags":["Reseller - Ports"]}},"/reseller/pool-keys":{"get":{"operationId":"list","parameters":[],"responses":{"200":{"description":"List of keys with usage and expiry info. Response carries `pak_` secret values — `Cache-Control: private, no-store` set so no CDN or shared proxy caches them."}},"security":[{"bearer":[]}],"summary":"List all pool access keys","tags":["Reseller - Pool Access Keys"]}},"/reseller/pool-keys/audit":{"get":{"description":"Recent forensic events for every pak_ owned by this reseller. Useful for \"what changed today / who used my keys\" overview. Filter by action via `?action=create|update|topup|regenerate|reveal|delete|gateway_auth_success|gateway_auth_failure|auto_suspended_cap_exceeded|auto_suspended_expired`. Paginate with `?before=<ISO>&limit=N` (limit max 500).","operationId":"getAuditLog","parameters":[{"name":"limit","required":true,"in":"query","schema":{"type":"string"}},{"name":"before","required":true,"in":"query","schema":{"type":"string"}},{"name":"action","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"Audit events (newest first)"}},"security":[{"bearer":[]}],"summary":"Audit log across all keys","tags":["Reseller - Pool Access Keys"]}},"/reseller/pool-keys/{keyId}/audit":{"get":{"description":"Recent forensic events for a single pak_. Returns 404 if the key is not owned by this reseller.","operationId":"getAuditLogForKey","parameters":[{"name":"keyId","required":true,"in":"path","schema":{"type":"string"}},{"name":"limit","required":true,"in":"query","schema":{"type":"string"}},{"name":"before","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"Audit events (newest first)"}},"security":[{"bearer":[]}],"summary":"Audit log for one key","tags":["Reseller - Pool Access Keys"]}},"/reseller/pool-keys/{keyId}/reveal":{"post":{"description":"Returns the full pak_ value AND records a `reveal` event in the audit log. The customer portal calls this when the user clicks \"Reveal\" on a masked key — gives forensic visibility into \"who exfiltrated my key\" investigations even when the action is legitimate. Frontend masks the pak_ in the table by default; this is the explicit-consent unmask path.","operationId":"reveal","parameters":[{"name":"keyId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"Full pak_ value + key metadata"}},"security":[{"bearer":[]}],"summary":"Reveal the full pak_ secret (audit-logged)","tags":["Reseller - Pool Access Keys"]}},"/reseller/pool-keys/{keyId}":{"get":{"description":"Cheaper than `list()` + filter when you already have the id. Returns 404 if the key does not exist or belongs to another reseller.","operationId":"get","parameters":[{"name":"keyId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"Key returned"},"404":{"description":"Key not found"}},"security":[{"bearer":[]}],"summary":"Get a single pool access key","tags":["Reseller - Pool Access Keys"]}},"/reseller/pool-keys/{keyId}/regenerate":{"post":{"description":"Rotates the secret pak_ value. The old value stops working immediately. Returns the FULL key record (since 0.3.0); previously returned `{id, key}` only.","operationId":"regenerate","parameters":[{"name":"keyId","required":true,"in":"path","schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Full key with new pak_ value"}},"security":[{"bearer":[]}],"summary":"Regenerate the key value","tags":["Reseller - Pool Access Keys"]}},"/admin/resellers/{resellerId}/api-keys":{"post":{"operationId":"createApiKey","parameters":[{"name":"resellerId","required":true,"in":"path","description":"Reseller user ID","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateApiKeyDto"},"examples":{"fullAccess":{"value":{"name":"Reseller Full Access","scopes":["customers:read","customers:write","ports:read","ports:write","webhooks:read","webhooks:write","billing:read","billing:write"]},"summary":"Full access key"},"readOnly":{"value":{"name":"Reseller Read Only","scopes":["customers:read","ports:read","billing:read"]},"summary":"Read-only key"}}}}},"responses":{"201":{"description":"API key created","content":{"application/json":{"schema":{"example":{"apiKey":"psx_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6","keyInfo":{"id":"507f1f77bcf86cd799439011","name":"Reseller Full Access","keyPrefix":"psx_a1b2c3d4","scopes":["customers:read","customers:write"],"isActive":true,"rateLimit":100}}}}}},"404":{"description":"Reseller not found"}},"security":[{"JWT-auth":[]}],"summary":"Create an API key for a reseller (Admin only)","tags":["Admin - Resellers"]}},"/admin/resellers/{resellerId}/activities":{"get":{"operationId":"getActivities","parameters":[{"name":"resellerId","required":true,"in":"path","description":"Reseller user ID","schema":{"type":"string"}},{"name":"type","required":false,"in":"query","description":"Filter by activity type","schema":{"type":"string"}},{"name":"limit","required":false,"in":"query","schema":{"type":"number"}},{"name":"skip","required":false,"in":"query","schema":{"type":"number"}}],"responses":{"200":{"description":"Activities retrieved successfully"}},"security":[{"JWT-auth":[]}],"summary":"Get activity log for a reseller (Admin only)","tags":["Admin - Resellers"]}},"/admin/resellers/{resellerId}/api-keys/{keyId}/revoke":{"post":{"operationId":"revokeApiKey","parameters":[{"name":"resellerId","required":true,"in":"path","description":"Reseller user ID","schema":{"type":"string"}},{"name":"keyId","required":true,"in":"path","description":"API key ID","schema":{"type":"string"}}],"responses":{"200":{"description":"API key revoked","content":{"application/json":{"schema":{"example":{"success":true,"message":"API key revoked"}}}}},"404":{"description":"Reseller or API key not found"}},"security":[{"JWT-auth":[]}],"summary":"Revoke an API key for a reseller (Admin only)","tags":["Admin - Resellers"]}},"/admin/resellers/{resellerId}/api-keys/{keyId}":{"delete":{"operationId":"deleteApiKey","parameters":[{"name":"resellerId","required":true,"in":"path","description":"Reseller user ID","schema":{"type":"string"}},{"name":"keyId","required":true,"in":"path","description":"API key ID","schema":{"type":"string"}}],"responses":{"200":{"description":"API key deleted","content":{"application/json":{"schema":{"example":{"success":true,"message":"API key deleted"}}}}},"404":{"description":"Reseller or API key not found"}},"security":[{"JWT-auth":[]}],"summary":"Delete an API key for a reseller (Admin only)","tags":["Admin - Resellers"]}},"/admin/resellers/{resellerId}/api-keys/{keyId}/regenerate":{"post":{"operationId":"regenerateApiKey","parameters":[{"name":"resellerId","required":true,"in":"path","description":"Reseller user ID","schema":{"type":"string"}},{"name":"keyId","required":true,"in":"path","description":"API key ID","schema":{"type":"string"}}],"responses":{"200":{"description":"API key regenerated","content":{"application/json":{"schema":{"example":{"apiKey":"psx_new_key_value_here_etc","keyInfo":{"id":"507f1f77bcf86cd799439011","name":"Reseller Full Access","keyPrefix":"psx_new_key","scopes":["customers:read","customers:write"],"isActive":true}}}}}},"404":{"description":"Reseller or API key not found"}},"security":[{"JWT-auth":[]}],"summary":"Regenerate an API key for a reseller (Admin only)","tags":["Admin - Resellers"]}},"/peer/register":{"post":{"operationId":"registerDevice","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegisterDeviceDto"}}}},"responses":{"201":{"description":"Device registered successfully"},"429":{"description":"Rate limit exceeded (5 per minute)"}},"summary":"Register a peer device","tags":["Peer Devices"]}},"/peer/token/{deviceId}/refresh":{"post":{"operationId":"refreshDeviceToken","parameters":[{"name":"deviceId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"Token refreshed"},"401":{"description":"Invalid or expired refresh token"},"404":{"description":"Device not found"}},"summary":"Refresh device token (requires refresh token)","tags":["Peer Devices"]}},"/peer/status/{deviceId}":{"put":{"operationId":"updateDeviceStatus","parameters":[{"name":"deviceId","required":true,"in":"path","schema":{"type":"string"}},{"name":"x-internal-key","required":true,"in":"header","schema":{"type":"string"}},{"name":"X-Internal-Key","in":"header","description":"Internal API key","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateDeviceStatusDto"}}}},"responses":{"200":{"description":"Status updated"},"401":{"description":"Unauthorized"},"404":{"description":"Device not found"}},"summary":"Update device status (relay server only)","tags":["Peer Devices"]}},"/peer/traffic/batch":{"post":{"operationId":"recordBatchTraffic","parameters":[{"name":"x-internal-key","required":true,"in":"header","schema":{"type":"string"}},{"name":"X-Internal-Key","in":"header","description":"Internal API key","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecordTrafficBatchDto"}}}},"responses":{"200":{"description":"Traffic entries recorded"},"401":{"description":"Unauthorized"}},"summary":"Record batch traffic entries (relay server only)","tags":["Peer Devices"]}},"/peer/traffic/{deviceId}":{"post":{"operationId":"recordTraffic","parameters":[{"name":"deviceId","required":true,"in":"path","schema":{"type":"string"}},{"name":"x-internal-key","required":true,"in":"header","schema":{"type":"string"}},{"name":"X-Internal-Key","in":"header","description":"Internal API key","schema":{"type":"string"}}],"responses":{"204":{"description":"Traffic recorded"},"401":{"description":"Unauthorized"}},"summary":"Record traffic usage (relay server only)","tags":["Peer Devices"]}},"/peer/device/{deviceId}":{"get":{"operationId":"getDevice","parameters":[{"name":"deviceId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"Device details"},"401":{"description":"Missing or invalid JWT token"},"403":{"description":"Cannot access another device's data"},"404":{"description":"Device not found"}},"security":[{"JWT-auth":[]}],"summary":"Get device details (authenticated)","tags":["Peer Devices"]}},"/peer/internal/device/{deviceId}":{"get":{"operationId":"getDeviceInternal","parameters":[{"name":"deviceId","required":true,"in":"path","schema":{"type":"string"}},{"name":"x-internal-key","required":true,"in":"header","schema":{"type":"string"}},{"name":"X-Internal-Key","in":"header","description":"Internal API key","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"summary":"Get device details (internal - relay server only)","tags":["Peer Devices"]}},"/peer/earnings/{deviceId}":{"get":{"operationId":"getDeviceEarnings","parameters":[{"name":"deviceId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"Earnings data"},"401":{"description":"Missing or invalid JWT token"},"403":{"description":"Cannot access another device's data"}},"security":[{"JWT-auth":[]}],"summary":"Get device earnings (authenticated)","tags":["Peer Devices"]}},"/peer/devices/{deviceId}/earnings":{"get":{"operationId":"getDetailedEarnings","parameters":[{"name":"deviceId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"Detailed earnings data"},"401":{"description":"Missing or invalid JWT token"},"403":{"description":"Cannot access another device's data"}},"security":[{"JWT-auth":[]}],"summary":"Get detailed earnings (authenticated)","tags":["Peer Devices"]}},"/peer/devices/{deviceId}/wallet":{"put":{"operationId":"updateWallet","parameters":[{"name":"deviceId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"Wallets updated"},"401":{"description":"Missing or invalid JWT token"},"403":{"description":"Cannot update another device's wallet"},"429":{"description":"Rate limit exceeded (1 per day)"}},"security":[{"JWT-auth":[]}],"summary":"Update wallet addresses (authenticated)","tags":["Peer Devices"]}},"/peer/devices/{deviceId}/rotate":{"post":{"operationId":"rotateDeviceIP","parameters":[{"name":"deviceId","required":true,"in":"path","schema":{"type":"string"}},{"name":"x-api-key","required":true,"in":"header","schema":{"type":"string"}},{"name":"x-internal-key","required":true,"in":"header","schema":{"type":"string"}},{"name":"X-API-Key","in":"header","description":"API key or internal key","schema":{"type":"string"}}],"responses":{"200":{"description":"Rotation result"},"404":{"description":"Device not found or offline"}},"summary":"Trigger IP rotation on device","tags":["Peer Devices"]}},"/peer/devices/{deviceId}/ip-changed":{"post":{"operationId":"recordIPChange","parameters":[{"name":"deviceId","required":true,"in":"path","schema":{"type":"string"}},{"name":"x-api-key","required":true,"in":"header","schema":{"type":"string"}},{"name":"X-API-Key","in":"header","description":"API key","schema":{"type":"string"}}],"responses":{"200":{"description":"IP change recorded"}},"summary":"Record IP change notification","tags":["Peer Devices"]}},"/peer/classify-ip":{"post":{"operationId":"classifyIP","parameters":[{"name":"x-internal-key","required":true,"in":"header","schema":{"type":"string"}},{"name":"X-Internal-Key","in":"header","description":"Internal API key","schema":{"type":"string"}}],"responses":{"200":{"description":"IP classification result"},"401":{"description":"Unauthorized"}},"summary":"Classify IP address (relay server only)","tags":["Peer Devices"]}},"/peer/my-devices":{"get":{"operationId":"getMyDevices","parameters":[],"responses":{"200":{"description":"Farmer peer devices with stats"}},"summary":"Get peer devices registered by the authenticated farmer","tags":["Peer Devices"]}},"/peer/claim-device":{"post":{"operationId":"claimDevice","parameters":[],"responses":{"200":{"description":"Device claimed"}},"summary":"Claim an unclaimed peer device and link to farmer account","tags":["Peer Devices"]}},"/peer/my-devices/{deviceId}/listing":{"patch":{"operationId":"toggleListing","parameters":[{"name":"deviceId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"Listing updated"}},"summary":"Toggle device listing for sale in pool gateway","tags":["Peer Devices"]}},"/peer/my-devices/{deviceId}/verification":{"get":{"operationId":"getDeviceVerification","parameters":[{"name":"deviceId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"summary":"Get device verification status and quality checks","tags":["Peer Devices"]}},"/peer/my-preferences":{"get":{"operationId":"getMyPreferences","parameters":[],"responses":{"200":{"description":""}},"summary":"Get farmer peer preferences (auto-list setting)","tags":["Peer Devices"]},"patch":{"operationId":"updateMyPreferences","parameters":[],"responses":{"200":{"description":""}},"summary":"Update farmer peer preferences (auto-list setting)","tags":["Peer Devices"]}},"/peer/my-devices/list-all":{"post":{"operationId":"listAllMyDevices","parameters":[],"responses":{"201":{"description":""}},"summary":"List all eligible online devices for sale","tags":["Peer Devices"]}},"/peer/admin/verification/stats":{"get":{"operationId":"getVerificationStats","parameters":[],"responses":{"200":{"description":""}},"summary":"Get marketplace verification statistics","tags":["Peer Devices"]}},"/peer/admin/verification/pending":{"get":{"operationId":"getPendingVerification","parameters":[{"name":"country","required":true,"in":"query","schema":{"type":"string"}},{"name":"ipType","required":true,"in":"query","schema":{"type":"string"}},{"name":"page","required":true,"in":"query","schema":{"type":"string"}},{"name":"limit","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"summary":"List devices pending verification","tags":["Peer Devices"]}},"/peer/admin/verification/{deviceId}/check":{"post":{"operationId":"runVerificationChecks","parameters":[{"name":"deviceId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"201":{"description":""}},"summary":"Run quality verification checks on a device","tags":["Peer Devices"]}},"/peer/admin/verification/{deviceId}/approve":{"post":{"operationId":"approveDevice","parameters":[{"name":"deviceId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"201":{"description":""}},"summary":"Approve device for marketplace listing","tags":["Peer Devices"]}},"/peer/admin/verification/{deviceId}/reject":{"post":{"operationId":"rejectDevice","parameters":[{"name":"deviceId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"201":{"description":""}},"summary":"Reject device from marketplace listing","tags":["Peer Devices"]}},"/peer/admin/verification/bulk-approve":{"post":{"operationId":"bulkApprove","parameters":[],"responses":{"201":{"description":""}},"summary":"Bulk approve devices for marketplace","tags":["Peer Devices"]}},"/peer/admin/verification/bulk-reject":{"post":{"operationId":"bulkReject","parameters":[],"responses":{"201":{"description":""}},"summary":"Bulk reject devices from marketplace","tags":["Peer Devices"]}},"/peer/admin/verification/bulk-verify":{"post":{"operationId":"bulkVerify","parameters":[],"responses":{"201":{"description":""}},"summary":"Run bulk auto-verification with filters","tags":["Peer Devices"]}},"/peer/admin/verification/bulk-unlist":{"post":{"operationId":"bulkUnlist","parameters":[],"responses":{"201":{"description":""}},"summary":"Bulk unlist devices by filter","tags":["Peer Devices"]}},"/peer/devices":{"get":{"operationId":"listDevices","parameters":[{"name":"status","required":true,"in":"query","schema":{"type":"string"}},{"name":"country","required":true,"in":"query","schema":{"type":"string"}},{"name":"page","required":true,"in":"query","schema":{"type":"string"}},{"name":"limit","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"Device list"}},"summary":"List peer devices","tags":["Peer Devices"]}},"/peer/stats/online":{"get":{"operationId":"getOnlineStats","parameters":[],"responses":{"200":{"description":"Online stats by country"}},"summary":"Get online device statistics","tags":["Peer Devices"]}},"/peer/verify-token":{"post":{"operationId":"verifyToken","parameters":[{"name":"x-internal-key","required":true,"in":"header","schema":{"type":"string"}},{"name":"X-Internal-Key","in":"header","description":"Internal API key","schema":{"type":"string"}}],"responses":{"200":{"description":"Token valid"},"401":{"description":"Invalid token or key"}},"summary":"Verify device token (relay server only)","tags":["Peer Devices"]}},"/peer/config":{"get":{"operationId":"getConfig","parameters":[],"responses":{"200":{"description":"SDK configuration"}},"summary":"Get SDK configuration","tags":["Peer Devices"]}},"/peer/board":{"get":{"operationId":"getBoardData","parameters":[],"responses":{"200":{"description":"Board data with peers and stats"},"429":{"description":"Too many requests"}},"summary":"Get peer board data for public display","tags":["Peer Devices"]}},"/peer/proxy/devices":{"get":{"operationId":"getOnlineDevices","parameters":[],"responses":{"200":{"description":"Online devices list"}},"summary":"List online peer devices","tags":["Peer Proxy"]}},"/peer/proxy/request":{"post":{"operationId":"proxyRequest","parameters":[{"name":"x-api-key","required":true,"in":"header","schema":{"type":"string"}},{"name":"X-API-Key","in":"header","description":"API key for authentication","schema":{"type":"string"}}],"responses":{"200":{"description":"Proxy response"},"503":{"description":"No devices available"}},"summary":"Make HTTP request through a peer device","tags":["Peer Proxy"]}},"/peer/proxy/test/{deviceId}":{"get":{"operationId":"testProxy","parameters":[{"name":"deviceId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"IP info from peer"}},"summary":"Test proxy connection to a device","tags":["Peer Proxy"]}},"/peer/proxy/connect-string/{deviceId}":{"get":{"operationId":"getConnectString","parameters":[{"name":"deviceId","required":true,"in":"path","schema":{"type":"string"}},{"name":"apiKey","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"Connection details"}},"summary":"Get proxy connection string for device","tags":["Peer Proxy"]}},"/peer/proxy/credentials":{"get":{"operationId":"getAllCredentials","parameters":[{"name":"apiKey","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"Proxy credentials for all online devices"}},"summary":"Get all online device proxy credentials","tags":["Peer Proxy"]}},"/peer/agents/register":{"post":{"description":"\nRegister your AI agent to earn USDC by sharing bandwidth.\n\n**IMPORTANT:** Save the JWT token returned! You'll need it for all other endpoints.\n\n## How It Works\n1. Call this endpoint with agent name and type\n2. **Save the JWT token** - it's your authentication for all other endpoints\n3. Connect to relay server via WebSocket with the JWT\n4. Handle proxy requests and route traffic\n5. Earn automatically: rate by IP tier (mobile > residential > datacenter); read `earningsPerGB` in the response for live values — set by platform, may change.\n\n## Rate Limit\n3 registrations per minute per IP address.\n\n## CAPTCHA (if enabled)\nInclude X-Captcha-Token header with hCaptcha/Turnstile response.\n\n## Agent Types\n- **claude**: Claude AI agents\n- **gpt**: OpenAI GPT agents\n- **custom**: Custom/other AI agents\n\n## Example\n```bash\ncurl -X POST https://api.proxies.sx/v1/peer/agents/register \\\n  -H \"Content-Type: application/json\" \\\n  -H \"X-Captcha-Token: optional-captcha-token\" \\\n  -d '{\"name\":\"my-agent\",\"type\":\"claude\"}'\n\n# Save the JWT from response for future API calls!\n```\n    ","operationId":"register","parameters":[{"name":"X-Captcha-Token","in":"header","description":"CAPTCHA response token (required if CAPTCHA_ENABLED=true)","required":false,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegisterAgentDto"}}}},"responses":{"201":{"description":"Agent registered successfully","content":{"application/json":{"schema":{"type":"object","properties":{"deviceId":{"type":"string","example":"agent_abc123def456"},"jwt":{"type":"string","example":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."},"refreshToken":{"type":"string","example":"abc123..."},"relay":{"type":"string","example":"wss://relay.proxies.sx"},"earningsPerGB":{"type":"object","description":"Live USD/GB rates by IP tier — set by platform, may change"},"instructions":{"type":"string"}}}}}},"400":{"description":"Invalid CAPTCHA token"},"429":{"description":"Rate limit exceeded (3 per minute)"}},"summary":"Register AI agent as bandwidth peer","tags":["Peer Agents"]}},"/peer/agents/stats/summary":{"get":{"description":"Get aggregate statistics for all agent peers. No authentication required.","operationId":"getStats","parameters":[],"responses":{"200":{"description":"Agent stats summary","content":{"application/json":{"schema":{"type":"object","properties":{"total":{"type":"number","example":50},"online":{"type":"number","example":12},"totalTrafficGB":{"type":"number","example":500},"totalEarnedUSD":{"type":"number","example":250}}}}}}},"summary":"Get agent statistics (public)","tags":["Peer Agents"]}},"/peer/agents/{id}/refresh":{"post":{"description":"\nGet a new JWT access token using your refresh token.\n\n**No JWT required** - this endpoint uses refresh token authentication.\n\nAccess tokens expire in 1 hour. Use this endpoint to get a new one.\n\n## Example\n```bash\ncurl -X POST https://api.proxies.sx/v1/peer/agents/agent_xxx/refresh \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"refreshToken\":\"your-refresh-token-from-registration\"}'\n```\n    ","operationId":"refreshToken","parameters":[{"name":"id","required":true,"in":"path","description":"Agent device ID (agent_xxx)","schema":{"type":"string"}}],"responses":{"200":{"description":"New access token issued","content":{"application/json":{"schema":{"type":"object","properties":{"jwt":{"type":"string"},"expiresIn":{"type":"string","example":"1h"}}}}}},"401":{"description":"Invalid or expired refresh token"},"429":{"description":"Rate limit exceeded"}},"summary":"Refresh access token","tags":["Peer Agents"]}},"/peer/agents/{id}/status":{"get":{"description":"\nCheck if agent is online, traffic stats, and earnings.\n\n**Authentication required:** Use the JWT from registration.\n\n```bash\ncurl https://api.proxies.sx/v1/peer/agents/agent_xxx/status \\\n  -H \"Authorization: Bearer <your-jwt-token>\"\n```\n    ","operationId":"getStatus","parameters":[{"name":"id","required":true,"in":"path","description":"Agent device ID (agent_xxx)","schema":{"type":"string"}}],"responses":{"200":{"description":"Agent status","content":{"application/json":{"schema":{"type":"object","properties":{"deviceId":{"type":"string"},"name":{"type":"string"},"type":{"type":"string"},"status":{"type":"string","enum":["online","offline"]},"currentIp":{"type":"string"},"lastSeenAt":{"type":"string","format":"date-time"},"totalTrafficMB":{"type":"number"},"totalEarnedCents":{"type":"number"},"sessionsCount":{"type":"number"}}}}}},"401":{"description":"Missing or invalid JWT token"},"403":{"description":"Cannot access another agent's data"},"404":{"description":"Agent not found"}},"security":[{"JWT-auth":[]}],"summary":"Get agent status (authenticated)","tags":["Peer Agents"]}},"/peer/agents/{id}/wallet":{"put":{"description":"\nUpdate the wallet address for payouts.\n\n**SECURITY:** Wallet changes trigger a 7-day cooling period before payouts.\n\n**Authentication required:** Use the JWT from registration.\n\n**Rate limit:** 1 change per 24 hours.\n\n```bash\ncurl -X PUT https://api.proxies.sx/v1/peer/agents/agent_xxx/wallet \\\n  -H \"Authorization: Bearer <your-jwt-token>\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"walletAddress\":\"6eUdVwsPArTxwVqEARYGCh4S2qwW2zCs7jSEDRpxydnv\"}'\n```\n    ","operationId":"updateWallet","parameters":[{"name":"id","required":true,"in":"path","description":"Agent device ID (agent_xxx)","schema":{"type":"string"}}],"responses":{"200":{"description":"Wallet updated (7-day cooling period activated)"},"401":{"description":"Missing or invalid JWT token"},"403":{"description":"Cannot update another agent's wallet"},"429":{"description":"Rate limit exceeded (1 per day)"}},"security":[{"JWT-auth":[]}],"summary":"Update agent wallet (authenticated)","tags":["Peer Agents"]}},"/peer/agents/{id}/withdraw":{"post":{"description":"\nRequest payout of pending earnings to your Solana wallet.\n\n**Authentication required:** Use the JWT from registration.\n\n## Requirements\n- Minimum payout: $5.00\n- Payment method: USDC on Solana\n- Processing time: 24-48 hours\n- Rate limit: 3 requests per hour\n\n## Example\n```bash\ncurl -X POST https://api.proxies.sx/v1/peer/agents/agent_xxx/withdraw \\\n  -H \"Authorization: Bearer <your-jwt-token>\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"walletAddress\":\"6eUdVwsPArTxwVqEARYGCh4S2qwW2zCs7jSEDRpxydnv\"}'\n```\n    ","operationId":"withdraw","parameters":[{"name":"id","required":true,"in":"path","description":"Agent device ID (agent_xxx)","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WithdrawAgentDto"}}}},"responses":{"200":{"description":"Withdrawal request submitted","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"message":{"type":"string"},"requestedAmountCents":{"type":"number"},"walletAddress":{"type":"string"}}}}}},"401":{"description":"Missing or invalid JWT token"},"403":{"description":"Cannot withdraw another agent's earnings"},"404":{"description":"Agent not found"},"429":{"description":"Rate limit exceeded (3 per hour)"}},"security":[{"JWT-auth":[]}],"summary":"Request earnings withdrawal (authenticated)","tags":["Peer Agents"]}},"/gateway/auth":{"post":{"description":"Called by the proxy gateway to authenticate customer requests. Requires internal API key. Returns user info and balance if valid.","operationId":"authenticateGateway","parameters":[{"name":"x-internal-key","required":true,"in":"header","schema":{"type":"string"}},{"name":"x-forwarded-for","required":true,"in":"header","schema":{"type":"string"}},{"name":"user-agent","required":true,"in":"header","schema":{"type":"string"}},{"name":"X-Internal-Key","in":"header","description":"Internal API key for gateway authentication","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GatewayAuthDto"}}}},"responses":{"200":{"description":"Authentication result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GatewayAuthResponseDto"}}}},"401":{"description":"Invalid internal key"}},"summary":"Authenticate proxy request (internal)","tags":["Gateway"]}},"/gateway/credentials":{"get":{"description":"Returns the proxy username and connection details for the authenticated user.","operationId":"getProxyCredentials","parameters":[],"responses":{"200":{"description":"Proxy credentials","content":{"application/json":{"schema":{"type":"object","properties":{"username":{"type":"string","example":"psx_abc123"},"password":{"type":"string","example":"(set via Account → Proxy Password)"},"httpProxy":{"type":"string","example":"http://psx_abc123:YOUR_PASSWORD@gw.proxies.sx:7000"},"socks5Proxy":{"type":"string","example":"socks5://psx_abc123:YOUR_PASSWORD@gw.proxies.sx:7001"}}}}}}},"security":[{"bearer":[]}],"summary":"Get proxy credentials","tags":["Gateway"]}},"/gateway/traffic/batch":{"post":{"description":"Called by the proxy gateway to record traffic usage. Requires internal API key. Stores per-user pool gateway traffic.","operationId":"recordTrafficBatch","parameters":[{"name":"x-internal-key","required":true,"in":"header","schema":{"type":"string"}},{"name":"X-Internal-Key","in":"header","description":"Internal API key for gateway","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Traffic recorded successfully"},"401":{"description":"Invalid internal key"}},"summary":"Record traffic batch (internal)","tags":["Gateway"]}},"/gateway/pool/availability":{"get":{"description":"Returns online device count for each country. Helps customers understand optimal proxy generation limits.","operationId":"getAvailability","parameters":[],"responses":{"200":{"description":"Device availability by country","content":{"application/json":{"schema":{"type":"object","properties":{"countries":{"type":"object","example":{"US":{"online":42,"total":45},"DE":{"online":26,"total":28},"ES":{"online":24,"total":26},"GB":{"online":22,"total":24},"PL":{"online":21,"total":22},"FR":{"online":17,"total":20}}},"totalOnline":{"type":"number","example":152},"totalDevices":{"type":"number","example":165}}}}}}},"summary":"Get device availability per country","tags":["Gateway Pool"]}},"/gateway/incidents":{"get":{"description":"Empty array when everything is nominal.","operationId":"getIncidents","parameters":[],"responses":{"200":{"description":"Incidents wrapped in { incidents: [...] }"}},"summary":"Active customer-facing pool incidents","tags":["Gateway Public"]}},"/gateway/pool/stock":{"get":{"description":"Lightweight JSON, cacheable 30s. Intended for landing page badges and the /v1/x402/stock aliases.","operationId":"getPoolStock","parameters":[],"responses":{"200":{"description":""}},"summary":"Flat pool stock listing (mbl + peer) by country","tags":["Gateway"]}},"/gateway/health":{"get":{"operationId":"healthCheck","parameters":[],"responses":{"200":{"description":"Service healthy"}},"summary":"Gateway service health check","tags":["Gateway"]}},"/gateway/pool/my-stats":{"get":{"description":"Returns personal pool usage (traffic, active connections) and aggregated pool health (total devices, countries available). Does NOT show individual modem details to customers.","operationId":"getMyPoolStats","parameters":[],"responses":{"200":{"description":"Personal pool stats","content":{"application/json":{"schema":{"type":"object","properties":{"myTrafficInMB":{"type":"number","example":512.5},"myTrafficOutMB":{"type":"number","example":256.3},"myTotalGB":{"type":"number","example":0.75},"myActiveConnections":{"type":"number","example":2},"poolTotalDevices":{"type":"number","example":155},"poolOnlineDevices":{"type":"number","example":152},"poolCountries":{"type":"array","items":{"type":"string"},"example":["US","DE","GB","ES","PL","FR"]},"poolHealthScore":{"type":"number","example":98}}}}}}},"security":[{"bearer":[]}],"summary":"Get my pool gateway stats","tags":["Gateway Pool"]}},"/gateway/pool/my-sessions":{"get":{"description":"Returns list of currently active proxy sessions with traffic stats, endpoint details, and load per modem. Pass ?pakId=pak_xxx to filter to one customer's sessions (multi-tenant resellers).","operationId":"getMyActiveSessions","parameters":[{"name":"pakId","required":false,"in":"query","description":"Optional pool-access-key value (pak_xxx) to scope to one customer","schema":{"type":"string"}}],"responses":{"200":{"description":"Active sessions list"}},"security":[{"bearer":[]}],"summary":"Get my active sessions","tags":["Gateway Pool"]},"delete":{"description":"Terminates every active gateway session for the authenticated user. Idempotent (returns count=0 when none exist).","operationId":"closeAllMySessions","parameters":[],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"summary":"Close ALL of my active sessions","tags":["Gateway Pool"]}},"/gateway/pool/sessions/active":{"get":{"description":"Returns all active gateway sessions with user info, traffic stats, and timing.","operationId":"getActiveSessions","parameters":[],"responses":{"200":{"description":"Active sessions"}},"security":[{"bearer":[]}],"summary":"Get active sessions","tags":["Gateway Pool"]}},"/gateway/pool/my-sessions/{sessionKey}":{"delete":{"description":"Closes a session you own (sessionKey must match your accountId). Returns 404 if you do not own it.","operationId":"closeMySession","parameters":[{"name":"sessionKey","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"summary":"Close one of my active sessions","tags":["Gateway Pool"]}},"/gateway/pool/sessions/{sessionKey}":{"delete":{"description":"Terminates a specific gateway session immediately.","operationId":"killSession","parameters":[{"name":"sessionKey","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"Session killed successfully"}},"security":[{"bearer":[]}],"summary":"Kill a session","tags":["Gateway Pool"]}},"/v1/peer-auth/register":{"post":{"operationId":"register","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegisterPeerDto"}}}},"responses":{"201":{"description":""}},"summary":"Register a new peer user account","tags":["Peer Auth"]}},"/v1/peer-auth/login":{"post":{"operationId":"login","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoginPeerDto"}}}},"responses":{"201":{"description":""}},"summary":"Login to peer portal","tags":["Peer Auth"]}},"/v1/peer-auth/profile":{"get":{"operationId":"getProfile","parameters":[],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"summary":"Get current user profile","tags":["Peer Auth"]}},"/v1/peer-auth/change-password":{"post":{"operationId":"changePassword","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdatePasswordDto"}}}},"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"summary":"Change password","tags":["Peer Auth"]}},"/v1/peer-account/devices/link":{"post":{"operationId":"linkDevice","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LinkDeviceDto"}}}},"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"summary":"Link a device to your account","tags":["Peer Account"]}},"/v1/peer-account/devices/{deviceId}":{"delete":{"operationId":"unlinkDevice","parameters":[{"name":"deviceId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"summary":"Unlink a device from your account","tags":["Peer Account"]}},"/v1/peer-account/wallets":{"get":{"operationId":"getWallets","parameters":[],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"summary":"Get configured wallet addresses","tags":["Peer Account"]},"put":{"operationId":"updateWallets","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateWalletsDto"}}}},"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"summary":"Update wallet addresses","tags":["Peer Account"]}},"/v1/peer-account/referrals":{"get":{"operationId":"getReferrals","parameters":[],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"summary":"Get referral stats and referred users","tags":["Peer Account"]}},"/v1/peer-account/profile":{"put":{"operationId":"updateProfile","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateProfileDto"}}}},"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"summary":"Update profile","tags":["Peer Account"]}},"/v1/developer-auth/register":{"post":{"operationId":"register","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegisterDeveloperDto"}}}},"responses":{"201":{"description":""}},"summary":"Register a new developer account (pending approval)","tags":["Developer Auth"]}},"/v1/developer-auth/login":{"post":{"operationId":"login","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoginDeveloperDto"}}}},"responses":{"201":{"description":""}},"summary":"Login to developer portal","tags":["Developer Auth"]}},"/v1/developer-auth/profile":{"get":{"operationId":"getProfile","parameters":[],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"summary":"Get current developer profile","tags":["Developer Auth"]}},"/v1/developer/apps":{"get":{"operationId":"getApps","parameters":[],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"summary":"List all apps","tags":["Developer"]},"post":{"operationId":"createApp","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateAppDto"}}}},"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"summary":"Register a new app","tags":["Developer"]}},"/v1/developer/apps/{appId}":{"get":{"operationId":"getApp","parameters":[{"name":"appId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"summary":"Get app details","tags":["Developer"]},"put":{"operationId":"updateApp","parameters":[{"name":"appId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateAppDto"}}}},"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"summary":"Update app details","tags":["Developer"]}},"/v1/developer/api-key":{"get":{"operationId":"getApiKey","parameters":[],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"summary":"Get API key (full key for copying)","tags":["Developer"]}},"/v1/developer/api-key/regenerate":{"post":{"operationId":"regenerateApiKey","parameters":[],"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"summary":"Regenerate API key (invalidates old key)","tags":["Developer"]}},"/v1/developer/earnings/by-app":{"get":{"operationId":"getEarningsByApp","parameters":[],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"summary":"Get earnings breakdown by app","tags":["Developer"]}},"/v1/developer/payout-details":{"put":{"operationId":"updatePayoutDetails","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdatePayoutDetailsDto"}}}},"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"summary":"Update payout details","tags":["Developer"]}},"/health":{"get":{"operationId":"health","parameters":[],"responses":{"200":{"description":"Service is healthy","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","example":"ok"},"timestamp":{"type":"string","example":"2024-01-15T12:00:00.000Z"},"uptime":{"type":"number","example":3600.5},"version":{"type":"string","example":"0.0.1"}}}}}}},"summary":"Health check endpoint","tags":["System"]}},"/.well-known/x402":{"get":{"operationId":"getWellKnownX402","parameters":[],"responses":{"200":{"description":""}},"tags":["Welcome"]}}},"info":{"title":"Proxies.sx Customer API","description":"\n# Proxies.sx Customer API\n\nWelcome to the Proxies.sx API documentation. This API allows you to manage mobile proxies programmatically.\n\n## Authentication\n\nAll API requests require authentication using either:\n- **JWT Bearer Token**: Obtain via `POST /v1/login/signin`\n- **API Key**: Create via the dashboard or `POST /v1/api-keys`\n\n### Using JWT Token\n```\nAuthorization: Bearer eyJhbGciOiJIUzI1NiIs...\n```\n\n### Using API Key\n```\nX-API-Key: psx_your_api_key_here\n```\n\n## Base URL\n```\nhttps://api.proxies.sx/v1\n```\n\n## Rate Limits\n- Authentication endpoints: 5 requests/minute\n- Port operations: 100 requests/minute\n- General endpoints: 200 requests/minute\n\n## Quick Start\n1. Login to get a JWT token\n2. Create an API key for programmatic access\n3. Use the Ports endpoints to manage your proxies\n        ","version":"1.0","contact":{}},"tags":[],"servers":[{"url":"/v1"}],"components":{"securitySchemes":{"JWT-auth":{"scheme":"bearer","bearerFormat":"JWT","type":"http","description":"Enter your JWT token from /login/signin"},"API-Key":{"type":"apiKey","in":"header","name":"X-API-Key","description":"Enter your API key (psx_...)"}},"schemas":{"CreateUserDto":{"type":"object","properties":{"email":{"type":"string","format":"email","description":"User email address","example":"user@example.com"},"password":{"type":"string","minLength":8,"pattern":"/^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d).{8,}$/","description":"User password (minimum 8 characters, must contain uppercase, lowercase, and number)","example":"SecurePass123"},"role":{"type":"string","enum":["customer","farmer","reseller"],"description":"User role","example":"customer","default":"customer"},"name":{"type":"string","description":"User full name","example":"John Doe"},"organization":{"type":"string","description":"User organization","example":"Tech Corp"},"purpose":{"type":"string","description":"Purpose of using the service","example":"Web scraping for market research"},"phone":{"type":"string","description":"User phone number","example":"+1-555-123-4567"},"website":{"type":"string","format":"uri","description":"User website URL","example":"https://example.com"},"country":{"type":"string","description":"User country","example":"United States"},"company":{"type":"string","description":"User company name","example":"Tech Solutions Inc."},"referralCode":{"type":"string","description":"Affiliate referral code","example":"JOHN5X2K"},"farmerId":{"type":"string","description":"Farmer tenant ID (for white-label registration)","example":"507f1f77bcf86cd799439011"},"telegram":{"type":"string","description":"Telegram username for follow-up","example":"@johndoe"},"targetDomains":{"description":"Target domains/websites they plan to use proxies with","example":["facebook.com","google.com","amazon.com"],"type":"array","items":{"type":"string"}},"useCase":{"type":"string","description":"Primary use case for proxies","example":"scraping","enum":["scraping","account_management","ad_verification","social_media","ecommerce","seo","other"]},"monthlyBudget":{"type":"string","description":"Expected monthly budget range","example":"$50-200","enum":["$0-50","$50-200","$200-500","$500+"]},"expectedTraffic":{"type":"string","description":"Expected monthly traffic usage","example":"10-50GB","enum":["1-10GB","10-50GB","50-100GB","100GB+"]}},"required":["email","password"]},"UserResponseDto":{"type":"object","properties":{"id":{"type":"string","description":"User ID","example":"507f1f77bcf86cd799439011"},"_id":{"type":"string","description":"User ID (alias for compatibility)","example":"507f1f77bcf86cd799439011"},"email":{"type":"string","description":"User email address","example":"user@example.com"},"role":{"enum":["admin","farmer","reseller","customer"],"type":"string","description":"User role","example":"customer"},"isActive":{"type":"boolean","description":"Whether the user is active","example":true},"isEmailVerified":{"type":"boolean","description":"Whether the user email is verified","example":true},"name":{"type":"string","description":"User full name","example":"John Doe"},"organization":{"type":"string","description":"User organization","example":"Tech Corp"},"purpose":{"type":"string","description":"Purpose of using the service","example":"Web scraping for market research"},"phone":{"type":"string","description":"User phone number","example":"+1-555-123-4567"},"website":{"type":"string","description":"User website URL","example":"https://example.com"},"country":{"type":"string","description":"User country","example":"United States"},"company":{"type":"string","description":"User company name","example":"Tech Solutions Inc."},"twoFAEnabled":{"type":"boolean","description":"Two-Factor Authentication enabled flag","example":false},"proxyUsername":{"type":"string","description":"Proxy username for gateway authentication","example":"psx_507f1f77bcf86cd799439011"},"hasProxyPassword":{"type":"boolean","description":"Whether user has set a proxy password","example":false},"createdAt":{"type":"number","description":"User creation timestamp","example":1701425400000},"updatedAt":{"type":"number","description":"User last update timestamp","example":1701425400000}},"required":["id","email","role","isActive","isEmailVerified","createdAt","updatedAt"]},"AuthResponseDto":{"type":"object","properties":{"user":{"description":"Authenticated user object","allOf":[{"$ref":"#/components/schemas/UserResponseDto"}]},"access_token":{"type":"string","description":"JWT access token to be used in Authorization header as Bearer token","example":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."}},"required":["user","access_token"]},"LoginUserDto":{"type":"object","properties":{"email":{"type":"string","format":"email","description":"User email address","example":"user@example.com"},"password":{"type":"string","maxLength":128,"description":"User password","example":"password123"},"otp":{"type":"string","description":"One-time password (OTP) from authenticator app (required if 2FA is enabled)","example":"123456"}},"required":["email","password"]},"CreateApiKeyDto":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":100,"pattern":"/^[a-zA-Z0-9\\-_\\s\\.]+$/","description":"Friendly name for the API key (alphanumeric, dash, underscore, space, period only)","example":"My MCP Server"},"scopes":{"description":"Permission scopes for the key","example":["ports:read","ports:write","billing:read"],"type":"array","items":{"type":"string"}},"expiresInDays":{"type":"number","minimum":0,"maximum":365,"description":"Days until the key expires (0 = never)","example":90},"rateLimit":{"type":"number","minimum":10,"maximum":1000,"description":"Requests per minute (default: 100)","example":100}},"required":["name"]},"UpdateUserDto":{"type":"object","properties":{"email":{"type":"string","format":"email","example":"user@example.com"},"password":{"type":"string","minLength":8,"pattern":"/^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d).{8,}$/","description":"New password (optional). 8+ chars, mixed case + digit."},"role":{"type":"string","enum":["customer","farmer","reseller","admin"],"description":"User role. Admin only."},"status":{"type":"string","enum":["active","suspended","deleted"],"description":"Account status. Admin only."},"isActive":{"type":"boolean","description":"Account isActive boolean. Admin only."},"name":{"type":"string","example":"John Doe"},"organization":{"type":"string","example":"Tech Corp"},"purpose":{"type":"string","example":"Web scraping"},"phone":{"type":"string","example":"+1-555-123-4567"},"website":{"type":"string","format":"uri","example":"https://example.com"},"country":{"type":"string","example":"United States"},"company":{"type":"string","example":"Tech Solutions Inc."},"telegram":{"type":"string","example":"@johndoe"},"targetDomains":{"type":"array","items":{"type":"string"}},"useCase":{"type":"string"},"monthlyBudget":{"type":"string"},"expectedTraffic":{"type":"string"},"proxyUsername":{"type":"string","description":"Reseller proxyUsername (psx_<userId>). Admin only."}}},"SessionResponseDto":{"type":"object","properties":{"sessionId":{"type":"string","description":"Session identifier (MongoDB _id from auth log)"},"accountId":{"type":"string","description":"Account ID used for login"},"ip":{"type":"string","description":"IP address of the session"},"country":{"type":"string","description":"Country ISO code (e.g., US, DE)"},"countryName":{"type":"string","description":"Full country name"},"city":{"type":"string","description":"City name"},"userAgent":{"type":"string","description":"User agent string"},"firstSeenAt":{"format":"date-time","type":"string","description":"First seen timestamp"},"lastSeenAt":{"format":"date-time","type":"string","description":"Last activity timestamp"},"authCount":{"type":"number","description":"Number of authentication attempts from this session"},"isCurrent":{"type":"boolean","description":"Whether this is the current session"}},"required":["sessionId","accountId","ip","firstSeenAt","lastSeenAt","authCount","isCurrent"]},"SessionListResponseDto":{"type":"object","properties":{"sessions":{"type":"array","items":{"$ref":"#/components/schemas/SessionResponseDto"}},"total":{"type":"number","description":"Total number of active sessions"}},"required":["sessions","total"]},"KillSessionsResponseDto":{"type":"object","properties":{"killedCount":{"type":"number","description":"Number of sessions killed"},"message":{"type":"string","description":"Success message"}},"required":["killedCount","message"]},"LoginHistoryEntryDto":{"type":"object","properties":{"_id":{"type":"string","description":"Entry ID"},"accountId":{"type":"string","description":"Account ID used for login"},"success":{"type":"boolean","description":"Whether authentication was successful"},"errorMessage":{"type":"string","description":"Error message if authentication failed"},"ip":{"type":"string","description":"IP address"},"country":{"type":"string","description":"Country ISO code"},"countryName":{"type":"string","description":"Full country name"},"city":{"type":"string","description":"City name"},"userAgent":{"type":"string","description":"User agent string"},"timestamp":{"format":"date-time","type":"string","description":"Timestamp of the authentication attempt"}},"required":["_id","accountId","success","ip","timestamp"]},"LoginHistoryResponseDto":{"type":"object","properties":{"entries":{"type":"array","items":{"$ref":"#/components/schemas/LoginHistoryEntryDto"}},"total":{"type":"number","description":"Total number of entries matching filter"},"limit":{"type":"number","description":"Limit used in query"},"offset":{"type":"number","description":"Offset used in query"}},"required":["entries","total","limit","offset"]},"CreateDeviceDto":{"type":"object","properties":{"type":{"enum":["phone","modem"],"type":"string","description":"Type of the device","example":"phone"},"name":{"type":"string","description":"Device name or identifier","example":"My iPhone 15"},"imei":{"type":"string","pattern":"^[0-9]{15}$","description":"Device IMEI (exactly 15 digits)","example":"123456789012345"},"serverId":{"type":"string","description":"Server ID where device is managed (mandatory)","example":"507f1f77bcf86cd799439011"},"status":{"enum":["active","inactive","maintenance","disabled"],"type":"string","description":"Device status","example":"active"},"resellerId":{"type":"string","description":"Reseller ID (optional link to user)","example":"507f1f77bcf86cd799439011"},"countryId":{"type":"string","description":"Country ID where device is located","example":"507f1f77bcf86cd799439011"},"regionId":{"type":"string","description":"Region/City ID where device is located","example":"507f1f77bcf86cd799439011"},"carrierId":{"type":"string","description":"Carrier ID for device network provider","example":"507f1f77bcf86cd799439011"},"isPrivate":{"type":"boolean","description":"Whether this device is private (exclusive 1 customer per modem)","example":false,"default":false}},"required":["type","name","imei","serverId"]},"DeviceResponseDto":{"type":"object","properties":{"id":{"type":"string","description":"Device ID","example":"507f1f77bcf86cd799439011"},"type":{"enum":["phone","modem"],"type":"string","description":"Device type","example":"modem"},"name":{"type":"string","description":"Device name","example":"iPhone 12 Pro"},"imei":{"type":"string","description":"Device IMEI","example":"123456789012345"},"status":{"enum":["active","inactive","maintenance","disabled"],"type":"string","description":"Device status","example":"active"},"userId":{"type":"string","description":"User ID (owner)","example":"507f1f77bcf86cd799439012"},"serverId":{"type":"string","description":"Server ID where device is managed","example":"507f1f77bcf86cd799439017"},"resellerId":{"type":"string","nullable":true,"description":"Reseller ID","example":"507f1f77bcf86cd799439013"},"countryId":{"type":"string","nullable":true,"description":"Country ID","example":"507f1f77bcf86cd799439014"},"regionId":{"type":"string","nullable":true,"description":"Region ID","example":"507f1f77bcf86cd799439015"},"carrierId":{"type":"string","nullable":true,"description":"Carrier ID","example":"507f1f77bcf86cd799439016"},"server":{"type":"object","description":"Server details"},"country":{"type":"object","description":"Country details"},"region":{"type":"object","description":"Region details"},"carrier":{"type":"object","description":"Carrier details"},"createdAt":{"type":"number","description":"Creation date","example":1697235780000},"updatedAt":{"type":"number","description":"Last update date","example":1697235780000},"isDeleted":{"type":"boolean"},"deletedAt":{"format":"date-time","type":"string"}},"required":["id","type","name","imei","status","userId","serverId","createdAt","updatedAt","isDeleted","deletedAt"]},"UpdateDeviceDto":{"type":"object","properties":{"type":{"enum":["phone","modem"],"type":"string","description":"Type of the device","example":"phone"},"name":{"type":"string","description":"Device name or identifier","example":"My Updated iPhone 15"},"serverId":{"type":"string","description":"Server ID where device is managed","example":"507f1f77bcf86cd799439011"},"status":{"enum":["active","inactive","maintenance","disabled"],"type":"string","description":"Device status","example":"active"},"resellerId":{"type":"string","description":"Reseller ID (optional link to user)","example":"507f1f77bcf86cd799439011"},"countryId":{"type":"string","description":"Country ID where device is located","example":"507f1f77bcf86cd799439011"},"regionId":{"type":"string","description":"Region/City ID where device is located","example":"507f1f77bcf86cd799439011"},"carrierId":{"type":"string","description":"Carrier ID for device network provider","example":"507f1f77bcf86cd799439011"},"isPrivate":{"type":"boolean","description":"Whether this device is private (exclusive 1 customer per modem)","example":false}}},"CreatePortDto":{"type":"object","properties":{"countryId":{"type":"string","description":"Country ID where the port should be created","example":"507f1f77bcf86cd799439011"},"cityId":{"type":"string","description":"City ID where the port should be created (optional - if not provided, any city in the country)","example":"507f1f77bcf86cd799439012"},"carrierId":{"type":"string","description":"Carrier ID for the port configuration (optional - if not provided, any carrier in the country)","example":"507f1f77bcf86cd799439013"},"exclusive":{"type":"boolean","description":"Whether this port should have exclusive access to the device (no other ports allowed on the same device)","example":false,"default":false},"userId":{"type":"string","description":"User ID for whom the port should be created (admin only)","example":"507f1f77bcf86cd799439014"},"expiresAt":{"type":"number","minimum":60,"maximum":31536000,"description":"Expires at in seconds from now. Min: 60 seconds (1 minute), Max: 31536000 seconds (1 year)","example":43200},"osFingerprint":{"type":"string","enum":["","android:1","android:3","macosx:3","macosx:4","ios:1","ios:2","windows:1"],"description":"OS fingerprint spoofing (p0f) - makes traffic appear as coming from a different operating system. Useful for bypassing OS detection.","example":"windows:1"},"isPrivate":{"type":"boolean","description":"Request a private device (exclusive 1 customer per modem). Private devices allow IP rotation via airplane mode and charge per GB. Only one port per private device allowed.","example":false,"default":false}},"required":["countryId","expiresAt"]},"PortResponseDto":{"type":"object","properties":{"_id":{"type":"string","description":"Port unique identifier","example":"507f1f77bcf86cd799439011"},"deviceId":{"type":"string","description":"Device ID associated with the port","example":"507f1f77bcf86cd799439012"},"customerId":{"type":"string","description":"Customer ID who owns the port","example":"507f1f77bcf86cd799439013"},"httpPort":{"type":"number","description":"HTTP proxy port number","example":45123},"socksPort":{"type":"number","description":"SOCKS proxy port number","example":45124},"serverIp":{"type":"string","description":"Server IP address for the proxy","example":"192.168.1.100"},"proxyLogin":{"type":"string","description":"Proxy authentication username","example":"user_abc123def456"},"proxyPassword":{"type":"string","description":"Proxy authentication password","example":"SecurePass123!"},"exclusive":{"type":"boolean","description":"Whether this port has exclusive access to the device","example":false},"createdAt":{"type":"string","description":"Port creation timestamp","example":"2023-10-13T10:30:00.000Z"},"updatedAt":{"type":"string","description":"Port last update timestamp","example":"2023-10-13T10:30:00.000Z"}},"required":["_id","deviceId","customerId","httpPort","socksPort","serverIp","proxyLogin","proxyPassword","exclusive","createdAt","updatedAt"]},"BulkPortItemDto":{"type":"object","properties":{"countryId":{"type":"string","description":"Country ID where the port should be created","example":"507f1f77bcf86cd799439011"},"cityId":{"type":"string","description":"City ID where the port should be created (optional)","example":"507f1f77bcf86cd799439012"},"carrierId":{"type":"string","description":"Carrier ID for the port configuration (optional)","example":"507f1f77bcf86cd799439013"},"exclusive":{"type":"boolean","description":"Whether this port should have exclusive access to the device","example":false,"default":false},"expiresAt":{"type":"number","minimum":60,"maximum":31536000,"description":"Expires at in seconds from now. Min: 60 seconds (1 minute), Max: 31536000 seconds (1 year)","example":43200},"osFingerprint":{"type":"string","enum":["","android:1","android:3","macosx:3","macosx:4","ios:1","ios:2","windows:1"],"description":"OS fingerprint spoofing (p0f) - makes traffic appear as coming from a different operating system","example":"windows:1"},"isPrivate":{"type":"boolean","description":"Request a private device (exclusive 1 customer per modem). Private devices allow IP rotation via airplane mode and charge per GB. Only one port per private device allowed.","example":false,"default":false}},"required":["countryId","expiresAt"]},"BulkCreatePortDto":{"type":"object","properties":{"ports":{"minItems":1,"maxItems":50,"description":"Array of port configurations to create (max 50 ports per request)","example":[{"countryId":"507f1f77bcf86cd799439011","expiresAt":43200},{"countryId":"507f1f77bcf86cd799439011","cityId":"507f1f77bcf86cd799439012","expiresAt":86400}],"type":"array","items":{"$ref":"#/components/schemas/BulkPortItemDto"}},"userId":{"type":"string","description":"User ID for whom the ports should be created (admin only)","example":"507f1f77bcf86cd799439014"}},"required":["ports"]},"BulkCreatePortResultDto":{"type":"object","properties":{"total":{"type":"number","description":"Total ports requested"},"success":{"type":"number","description":"Number of ports successfully created"},"failed":{"type":"number","description":"Number of ports that failed to create"},"created":{"description":"Array of successfully created ports","type":"array","items":{"type":"object"}},"errors":{"type":"array","items":{"type":"object","properties":{"index":{"type":"number"},"error":{"type":"string"}},"required":["index","error"]}}},"required":["total","success","failed","created","errors"]},"DeletePortResponseDto":{"type":"object","properties":{"message":{"type":"string","description":"Success message confirming port deletion","example":"Port deleted successfully"}},"required":["message"]},"UpdatePortCredentialsDto":{"type":"object","properties":{"proxyLogin":{"type":"string","minLength":3,"maxLength":32,"pattern":"/^[a-zA-Z0-9_-]+$/","description":"New proxy username (3-32 characters, alphanumeric with underscores and hyphens)","example":"user_abc123"},"proxyPassword":{"type":"string","minLength":8,"maxLength":64,"pattern":"/^[a-zA-Z0-9!@#$%^&*()_+=\\[\\]{}|:;,.<>?~-]+$/","description":"New proxy password (8-64 characters, alphanumeric with safe special characters)","example":"SecurePass123"}}},"UpdateOsFingerprintDto":{"type":"object","properties":{"osFingerprint":{"type":"string","enum":["","android:1","android:3","macosx:3","macosx:4","ios:1","ios:2","windows:1"],"description":"OS fingerprint spoofing (p0f) - makes traffic appear as coming from a different operating system. Use empty string to disable.","example":"windows:1"}},"required":["osFingerprint"]},"PortStatusResponseDto":{"type":"object","properties":{"status":{"type":"string","description":"Online/offline status of the port","example":"online"},"isActive":{"type":"boolean","description":"Whether the port is active","example":true},"lastChecked":{"type":"string","description":"Last status check timestamp","example":"2023-10-13T12:00:00.000Z"}},"required":["status","isActive","lastChecked"]},"PortIpResponseDto":{"type":"object","properties":{"publicIp":{"type":"string","description":"Public IP address assigned to the port","example":"203.0.113.42"},"serverIp":{"type":"string","description":"Server IP address used by the proxy","example":"192.168.1.100"}},"required":["publicIp","serverIp"]},"PortSpeedTestResponseDto":{"type":"object","properties":{"downloadSpeed":{"type":"number","description":"Download speed in Mbps","example":85},"uploadSpeed":{"type":"number","description":"Upload speed in Mbps","example":32},"ping":{"type":"number","description":"Ping in milliseconds","example":45},"testTime":{"type":"string","description":"Timestamp of the speed test","example":"2023-10-13T12:05:00.000Z"}},"required":["downloadSpeed","uploadSpeed","ping","testTime"]},"PortPingResponseDto":{"type":"object","properties":{"success":{"type":"boolean","description":"Whether the ping was successful","example":true},"ip":{"type":"string","description":"IP address returned by the proxy","example":"203.0.113.42"},"responseTime":{"type":"number","description":"Response time in milliseconds","example":245},"testTime":{"type":"string","description":"Timestamp of the ping test","example":"2023-10-13T12:05:00.000Z"},"error":{"type":"string","description":"Error message if ping failed","example":null}},"required":["success","ip","responseTime","testTime"]},"ReconfigurePortDto":{"type":"object","properties":{"countryId":{"type":"string","description":"New country ID for the port","example":"507f1f77bcf86cd799439011"},"cityId":{"type":"string","description":"New city ID for the port (optional)","example":"507f1f77bcf86cd799439012"},"carrierId":{"type":"string","description":"New carrier ID for the port (optional)","example":"507f1f77bcf86cd799439013"},"isPrivate":{"type":"boolean","description":"Whether to reconfigure to a private device only (for private ports)","example":false}},"required":["countryId"]},"RotatePortDto":{"type":"object","properties":{"force":{"type":"boolean","description":"Force rotation even if rate limit not met (admin only)","example":false}}},"UpdateRotationSettingsDto":{"type":"object","properties":{"enabled":{"type":"boolean","description":"Enable or disable auto-rotation","example":true},"intervalSeconds":{"type":"number","minimum":60,"maximum":86400,"description":"Rotation interval in SECONDS. Min 60s (1 min) for private devices, 300s (5 min) for shared devices. Max 86400s (24 hours)","example":1200},"matchCarrier":{"type":"boolean","description":"Only rotate to devices with matching carrier","example":false},"matchCity":{"type":"boolean","description":"Only rotate to devices with matching city","example":false},"excludedDeviceIds":{"description":"Device IDs to exclude from rotation","example":["507f1f77bcf86cd799439011"],"type":"array","items":{"type":"string"}}}},"UpdateAutoRenewalDto":{"type":"object","properties":{"enabled":{"type":"boolean","description":"Enable or disable auto-renewal"},"source":{"type":"string","description":"Payment source for auto-renewal","enum":["balance","stripe"],"default":"balance"},"renewalDays":{"type":"number","minimum":1,"maximum":365,"description":"Number of days to renew for (default 30)","default":30}}},"PortDefaultsDto":{"type":"object","properties":{"defaultBandwidthIn":{"type":"number","description":"Default bandwidth in (mbps)","example":12},"defaultBandwidthOut":{"type":"number","description":"Default bandwidth out (mbps)","example":12},"defaultMaxConn":{"type":"number","description":"Default max connections (MAXCONN)","example":100},"defaultConnLim":{"type":"number","description":"Default connection limit per 60s (CONNLIM)","example":50},"softMaxPortsPerDevice":{"type":"number","description":"Soft max ports per device (guideline)","example":3},"maxPortsPerDevice":{"type":"number","description":"Hard max ports per device (enforced limit)","example":5}}},"CreateServerDto":{"type":"object","properties":{"name":{"type":"string","description":"Server name","example":"Production Server 1"},"description":{"type":"string","description":"Server description","example":"Main production server for device management"},"service":{"enum":["proxysmart","iproxy"],"type":"string","description":"Server service type","example":"proxysmart"},"serverIp":{"type":"string","description":"Server IP address (required for proxysmart)","example":"192.168.1.100"},"serverLogin":{"type":"string","description":"Server login (required for proxysmart)","example":"admin"},"serverPassword":{"type":"string","description":"Server password (required for proxysmart)","example":"password123"},"serverAuthToken":{"type":"string","description":"Server auth token (required for iproxy)","example":"abc123def456ghi789"},"farmerId":{"type":"string","description":"Farmer ID (admin only). If not provided, the authenticated user will be used.","example":"66f1a4b2c3d4e5f678901234"},"countryId":{"type":"string","description":"Country ID - primary country for this server (used for device filtering)","example":"69276bf1f547dfc948699263"},"httpPortRange":{"type":"object","properties":{"start":{"type":"number"},"end":{"type":"number"}},"required":["start","end"]},"socksPortRange":{"type":"object","properties":{"start":{"type":"number"},"end":{"type":"number"}},"required":["start","end"]},"portDefaults":{"description":"Port default settings for ProxySmart servers","allOf":[{"$ref":"#/components/schemas/PortDefaultsDto"}]}},"required":["name","description","service"]},"PortDefaultsResponseDto":{"type":"object","properties":{"defaultBandwidthIn":{"type":"number","description":"Default bandwidth in (mbps)","example":12},"defaultBandwidthOut":{"type":"number","description":"Default bandwidth out (mbps)","example":12},"defaultMaxConn":{"type":"number","description":"Default max connections (MAXCONN)","example":100},"defaultConnLim":{"type":"number","description":"Default connection limit per 60s (CONNLIM)","example":50},"softMaxPortsPerDevice":{"type":"number","description":"Soft max ports per device (guideline)","example":3},"maxPortsPerDevice":{"type":"number","description":"Hard max ports per device (enforced limit)","example":5}}},"ServerResponseDto":{"type":"object","properties":{"_id":{"type":"string","description":"Server ID","example":"507f1f77bcf86cd799439011"},"name":{"type":"string","description":"Server name","example":"Production Server 1"},"description":{"type":"string","description":"Server description","example":"Main production server for device management"},"service":{"enum":["proxysmart","iproxy"],"type":"string","description":"Server service type","example":"proxysmart"},"serverIp":{"type":"string","description":"Server IP address","example":"192.168.1.100"},"serverLogin":{"type":"string","description":"Server login","example":"admin"},"serverPassword":{"type":"string","description":"Server password (returned for admin convenience)","example":"password123"},"serverAuthToken":{"type":"string","description":"Server auth token","example":"abc123def456ghi789"},"farmerId":{"type":"string","description":"Farmer (owner) ID","example":"507f1f77bcf86cd799439012"},"status":{"enum":["online","offline","disabled"],"type":"string","description":"Server status","example":"online"},"portDefaults":{"description":"Port default settings for ProxySmart servers","allOf":[{"$ref":"#/components/schemas/PortDefaultsResponseDto"}]},"createdAt":{"type":"number","description":"Creation date","example":1697235780000},"updatedAt":{"type":"number","description":"Last update date","example":1697235780000}},"required":["_id","name","description","service","farmerId","status","createdAt","updatedAt"]},"UpdatePortDefaultsDto":{"type":"object","properties":{"defaultBandwidthIn":{"type":"number","description":"Default bandwidth in (mbps)","example":12},"defaultBandwidthOut":{"type":"number","description":"Default bandwidth out (mbps)","example":12},"defaultMaxConn":{"type":"number","description":"Default max connections (MAXCONN)","example":100},"defaultConnLim":{"type":"number","description":"Default connection limit per 60s (CONNLIM)","example":50},"softMaxPortsPerDevice":{"type":"number","description":"Soft max ports per device (guideline)","example":3},"maxPortsPerDevice":{"type":"number","description":"Hard max ports per device (enforced limit)","example":5}}},"UpdateServerDto":{"type":"object","properties":{"name":{"type":"string","description":"Server name","example":"Production Server 1"},"description":{"type":"string","description":"Server description","example":"Main production server for device management"},"service":{"enum":["proxysmart","iproxy"],"type":"string","description":"Server service type","example":"proxysmart"},"serverIp":{"type":"string","description":"Server IP address (required for proxysmart)","example":"192.168.1.100"},"serverLogin":{"type":"string","description":"Server login (required for proxysmart)","example":"admin"},"serverPassword":{"type":"string","description":"Server password (required for proxysmart)","example":"password123"},"serverAuthToken":{"type":"string","description":"Server auth token (required for iproxy)","example":"abc123def456ghi789"},"farmerId":{"type":"string","description":"Farmer ID (admin only). If not provided, the authenticated user will be used.","example":"66f1a4b2c3d4e5f678901234"},"countryId":{"type":"string","description":"Country ID - primary country for this server (used for device filtering)","example":"69276bf1f547dfc948699263"},"httpPortRange":{"type":"object","properties":{"start":{"type":"number"},"end":{"type":"number"}},"required":["start","end"]},"socksPortRange":{"type":"object","properties":{"start":{"type":"number"},"end":{"type":"number"}},"required":["start","end"]},"portDefaults":{"description":"Port default settings for ProxySmart servers","allOf":[{"$ref":"#/components/schemas/UpdatePortDefaultsDto"}]}}},"DeviceInfoDto":{"type":"object","properties":{"id":{"type":"string","description":"Device ID","example":"device-001"},"name":{"type":"string","description":"Device name","example":"iPhone 12 Pro"},"status":{"type":"string","description":"Device status","enum":["online","offline"],"example":"online"},"ip":{"type":"string","description":"Device IP address","example":"192.168.1.100"},"lastSeen":{"type":"number","description":"Last seen timestamp","example":1697234340000}},"required":["id","name","status","lastSeen"]},"DeviceOperationResponseDto":{"type":"object","properties":{"success":{"type":"boolean","description":"Operation success status","example":true},"message":{"type":"string","description":"Response message","example":"Device rotation initiated successfully"}},"required":["success","message"]},"DeviceStatusResponseDto":{"type":"object","properties":{"deviceId":{"type":"string","description":"Device ID","example":"device-001"},"status":{"type":"string","description":"Device status","enum":["online","offline"],"example":"online"},"uptime":{"type":"number","description":"Device uptime in seconds","example":3600},"lastChecked":{"type":"number","description":"Last checked timestamp","example":1697234340000}},"required":["deviceId","status","lastChecked"]},"ServerHealthResponseDto":{"type":"object","properties":{"healthy":{"type":"boolean","description":"Server health status","example":true},"message":{"type":"string","description":"Health status message","example":"Server is healthy and responding"},"responseTime":{"type":"number","description":"Response time in milliseconds","example":150}},"required":["healthy","message"]},"InvoiceItemDto":{"type":"object","properties":{"description":{"type":"string","description":"Item description","example":"10 Proxy Ports - Germany"},"type":{"enum":["Ports","Traffic","PortsShared","PortsPrivate","TrafficShared","TrafficPrivate"],"type":"string","description":"Item type (ports or traffic)"},"quantity":{"type":"number","minimum":1,"description":"Quantity","example":10},"unitPrice":{"type":"number","minimum":0,"description":"Unit price in USD","example":5},"total":{"type":"number","minimum":0,"description":"Total for this item","example":50},"tariffId":{"type":"string","description":"Associated tariff ID"}},"required":["description","type","quantity","unitPrice","total"]},"CreateInvoiceDto":{"type":"object","properties":{"userId":{"type":"string","description":"User ID"},"items":{"description":"Invoice line items","type":"array","items":{"$ref":"#/components/schemas/InvoiceItemDto"}},"taxRate":{"type":"number","description":"Tax rate (0-1)","example":0.19},"paymentMethod":{"enum":["stripe","usdt","balance","admin"],"type":"string","description":"Payment method used"},"paymentId":{"type":"string","description":"Payment ID reference"},"purchaseId":{"type":"string","description":"Purchase ID reference"},"dueDate":{"type":"number","description":"Due date timestamp"},"notes":{"type":"string","description":"Invoice notes"},"billingAddress":{"type":"string","description":"Billing address"}},"required":["userId","items"]},"InvoiceResponseDto":{"type":"object","properties":{"_id":{"type":"string","description":"Invoice ID"},"invoiceNumber":{"type":"string","description":"Invoice number","example":"INV-2025-000001"},"userId":{"type":"string","description":"User ID"},"items":{"type":"array","items":{"$ref":"#/components/schemas/InvoiceItemDto"}},"subtotal":{"type":"number","description":"Subtotal before tax"},"tax":{"type":"number","description":"Tax amount"},"taxRate":{"type":"number","description":"Tax rate applied"},"total":{"type":"number","description":"Total amount"},"status":{"enum":["draft","pending","paid","cancelled","refunded"],"type":"string"},"paymentMethod":{"enum":["stripe","usdt","balance","admin"],"type":"string"},"paymentId":{"type":"string","description":"Payment ID"},"purchaseId":{"type":"string","description":"Purchase ID"},"paidAt":{"type":"number","description":"Paid timestamp"},"dueDate":{"type":"number","description":"Due date timestamp"},"notes":{"type":"string","description":"Notes"},"billingAddress":{"type":"string","description":"Billing address"},"createdAt":{"type":"number","description":"Created timestamp"},"updatedAt":{"type":"number","description":"Updated timestamp"}},"required":["_id","invoiceNumber","userId","items","subtotal","tax","taxRate","total","status","createdAt","updatedAt"]},"InvoiceListResponseDto":{"type":"object","properties":{"invoices":{"type":"array","items":{"$ref":"#/components/schemas/InvoiceResponseDto"}},"total":{"type":"number","description":"Total count"},"page":{"type":"number","description":"Current page"},"totalPages":{"type":"number","description":"Total pages"}},"required":["invoices","total","page","totalPages"]},"UpdateInvoiceStatusDto":{"type":"object","properties":{"status":{"enum":["draft","pending","paid","cancelled","refunded"],"type":"string","description":"New invoice status"},"paymentMethod":{"enum":["stripe","usdt","balance","admin"],"type":"string","description":"Payment method"},"paymentId":{"type":"string","description":"Payment ID reference"}},"required":["status"]},"CreateMessageDto":{"type":"object","properties":{"recipientId":{"type":"string","description":"Recipient user ID (MongoDB string id)"},"content":{"type":"string","maxLength":10000,"description":"Message content"},"status":{"enum":["sent","read"],"type":"string","description":"Initial message status"}},"required":["recipientId","content"]},"MessageDto":{"type":"object","properties":{"id":{"type":"string","description":"Message unique identifier (UUID)","example":"3b0e0b6e-6d3f-4e38-83f0-1d2c5a8a3c10"},"senderId":{"type":"string","description":"Sender user ID (Mongo ObjectId as string)","example":"656a9d4d8f1b2c3d4e5f6a7b"},"recipientId":{"type":"string","description":"Recipient user ID (Mongo ObjectId as string)","example":"656a9d4d8f1b2c3d4e5f6a7c"},"content":{"type":"string","description":"Message content text","example":"Hello! Are you available for a quick call?"},"status":{"enum":["sent","read"],"type":"string","description":"Message delivery status","example":"sent"},"createdAt":{"type":"number","description":"Creation timestamp","example":1736936625000},"updatedAt":{"type":"number","description":"Last update timestamp","example":1736936625000}},"required":["id","senderId","recipientId","content","status","createdAt","updatedAt"]},"PaginatedMessagesDto":{"type":"object","properties":{"total":{"type":"number","description":"Total number of messages","example":124},"items":{"description":"Messages in current page","type":"array","items":{"$ref":"#/components/schemas/MessageDto"}}},"required":["total","items"]},"RangeDto":{"type":"object","properties":{"min":{"type":"number","minimum":0,"description":"Minimum value"},"max":{"type":"number","minimum":0,"description":"Maximum value"}},"required":["min","max"]},"CreateTariffDto":{"type":"object","properties":{"portRange":{"nullable":true,"description":"Port range (required for Ports and Both types)","allOf":[{"$ref":"#/components/schemas/RangeDto"}]},"trafficRange":{"nullable":true,"description":"Traffic range (required for Traffic and Both types)","allOf":[{"$ref":"#/components/schemas/RangeDto"}]},"price":{"type":"number","minimum":0,"description":"Tariff price"},"type":{"enum":["Ports","Traffic","PortsShared","PortsPrivate","TrafficShared","TrafficPrivate"],"type":"string","description":"Tariff type","example":"Ports"}},"required":["price","type"]},"RangeResponseDto":{"type":"object","properties":{"min":{"type":"number","description":"Minimum value","example":1},"max":{"type":"number","description":"Maximum value","example":10}},"required":["min","max"]},"TariffResponseDto":{"type":"object","properties":{"_id":{"type":"string","description":"Tariff unique identifier","example":"507f1f77bcf86cd799439011"},"portRange":{"nullable":true,"description":"Port range (present for Ports tariffs)","example":{"min":1,"max":10},"allOf":[{"$ref":"#/components/schemas/RangeResponseDto"}]},"trafficRange":{"nullable":true,"description":"Traffic range in GB (present for Traffic tariffs)","example":{"min":100,"max":500},"allOf":[{"$ref":"#/components/schemas/RangeResponseDto"}]},"price":{"type":"number","description":"Tariff price in USD (per slot for ports, per GB for traffic)","example":10},"type":{"enum":["Ports","Traffic","PortsShared","PortsPrivate","TrafficShared","TrafficPrivate"],"type":"string","description":"Tariff type","example":"PortsShared"},"category":{"type":"string","description":"Tariff category: shared, private, or legacy","enum":["shared","private","legacy"],"example":"shared"},"resourceType":{"type":"string","description":"Type of resource this tariff applies to","enum":["ports","traffic"],"example":"ports"},"pricePerUnit":{"type":"number","description":"Price per unit (per slot for ports, per GB for traffic)","example":10},"unitType":{"type":"string","description":"Unit type for pricing","enum":["slot","gb"],"example":"slot"},"billingPeriod":{"type":"string","description":"Billing period: monthly for slots, one-time for traffic","enum":["monthly","one-time"],"example":"monthly"},"displayName":{"type":"string","description":"Human-readable display name","example":"Shared Port Slots (1-10)"},"description":{"type":"string","description":"Description of what this tariff covers","example":"Monthly subscription for shared proxy ports"},"createdAt":{"type":"number","description":"Creation timestamp (Unix milliseconds)","example":1729592400000},"updatedAt":{"type":"number","description":"Last update timestamp (Unix milliseconds)","example":1729592400000}},"required":["_id","price","type","category","resourceType","pricePerUnit","unitType","billingPeriod","displayName","description","createdAt","updatedAt"]},"UpdateTariffDto":{"type":"object","properties":{"portRange":{"nullable":true,"description":"Port range (required for Ports and Both types)","allOf":[{"$ref":"#/components/schemas/RangeDto"}]},"trafficRange":{"nullable":true,"description":"Traffic range (required for Traffic and Both types)","allOf":[{"$ref":"#/components/schemas/RangeDto"}]},"price":{"type":"number","minimum":0,"description":"Tariff price"},"type":{"enum":["Ports","Traffic","PortsShared","PortsPrivate","TrafficShared","TrafficPrivate"],"type":"string","description":"Tariff type","example":"Ports"}}},"CreateOrderDto":{"type":"object","properties":{"amount":{"type":"number","minimum":10,"maximum":1000,"description":"Amount to top up in USD","example":50},"currency":{"type":"string","description":"Currency for pricing (default: USD)","example":"USD","default":"USD"}},"required":["amount"]},"CreateOrderResponseDto":{"type":"object","properties":{"orderId":{"type":"string","description":"Internal order ID","example":"topup_abc123_1702134567890"},"coingateOrderId":{"type":"number","description":"CoinGate order ID","example":123456},"paymentUrl":{"type":"string","description":"URL to redirect user to CoinGate payment page","example":"https://pay.coingate.com/invoice/abc123"},"amount":{"type":"number","description":"Amount in USD","example":50},"currency":{"type":"string","description":"Currency","example":"USD"},"status":{"type":"string","description":"Order status","example":"new"},"createdAt":{"format":"date-time","type":"string","description":"Order creation timestamp"}},"required":["orderId","coingateOrderId","paymentUrl","amount","currency","status","createdAt"]},"OrderStatusDto":{"type":"object","properties":{"orderId":{"type":"string","description":"Internal order ID"},"coingateOrderId":{"type":"number","description":"CoinGate order ID"},"status":{"type":"string","description":"Order status","enum":["new","pending","confirming","paid","invalid","expired","canceled","refunded"]},"priceAmount":{"type":"number","description":"Price amount in USD"},"priceCurrency":{"type":"string","description":"Pricing currency"},"receiveAmount":{"type":"number","description":"Amount received after fees"},"payAmount":{"type":"number","description":"Crypto amount paid"},"payCurrency":{"type":"string","description":"Cryptocurrency used"},"paymentUrl":{"type":"string","description":"Payment URL for incomplete orders"},"balanceCredited":{"type":"boolean","description":"Whether balance was credited"},"createdAt":{"format":"date-time","type":"string","description":"Order creation timestamp"},"paidAt":{"format":"date-time","type":"string","nullable":true,"description":"Payment completion timestamp"}},"required":["orderId","coingateOrderId","status","priceAmount","priceCurrency","paymentUrl","balanceCredited","createdAt"]},"OrderHistoryDto":{"type":"object","properties":{"orderId":{"type":"string","description":"Internal order ID"},"status":{"type":"string","description":"Order status"},"priceAmount":{"type":"number","description":"Price amount"},"priceCurrency":{"type":"string","description":"Currency"},"payCurrency":{"type":"string","description":"Crypto used for payment"},"balanceCredited":{"type":"boolean","description":"Whether balance was credited"},"createdAt":{"format":"date-time","type":"string","description":"Order creation timestamp"},"paidAt":{"format":"date-time","type":"string","nullable":true,"description":"Payment completion timestamp"},"paymentUrl":{"type":"string","description":"Payment URL (for pending payments)"},"expiresAt":{"format":"date-time","type":"string","nullable":true,"description":"Order expiry timestamp"}},"required":["orderId","status","priceAmount","priceCurrency","balanceCredited","createdAt"]},"TopUpTrafficDto":{"type":"object","properties":{"userId":{"type":"string"},"trafficIn":{"type":"number","minimum":0},"trafficOut":{"type":"number","minimum":0}},"required":["userId","trafficIn","trafficOut"]},"CreatePaymentIntentDto":{"type":"object","properties":{"amount":{"type":"number","minimum":1,"description":"Amount in cents (e.g., 1000 = $10.00)","example":1000},"currency":{"type":"string","default":"usd","description":"Currency code","example":"usd"},"customerId":{"type":"string","description":"Customer ID","example":"cus_xxxxxxxxxxxxx"}},"required":["amount"]},"PaymentIntentResponseDto":{"type":"object","properties":{"clientSecret":{"type":"string","description":"Client secret for confirming payment on frontend","example":"pi_xxxxxxxxxxxxx_secret_xxxxxxxxxxxxx"},"paymentIntentId":{"type":"string","description":"Payment intent ID","example":"pi_xxxxxxxxxxxxx"},"status":{"type":"string","description":"Payment intent status","example":"requires_payment_method","enum":["requires_payment_method","requires_confirmation","requires_action","processing","requires_capture","canceled","succeeded"]}},"required":["clientSecret","paymentIntentId","status"]},"SetupPaymentIntentDto":{"type":"object","properties":{"email":{"type":"string","format":"email","description":"Customer email address","example":"customer@example.com"}},"required":["email"]},"SetupPaymentIntentResponseDto":{"type":"object","properties":{"clientSecret":{"type":"string","description":"Client secret for setting up payment method on frontend","example":"seti_xxxxxxxxxxxxx_secret_xxxxxxxxxxxxx"}},"required":["clientSecret"]},"PayUsingSavedCardDto":{"type":"object","properties":{"amount":{"type":"number","minimum":0.01,"description":"Amount in DOLLARS (e.g., 10 = $10.00, 55.50 = $55.50). Backend will convert to cents for Stripe.","example":10},"currency":{"type":"string","default":"usd","description":"Currency code","example":"usd"},"metadata":{"type":"object","description":"Optional metadata","example":{"orderId":"12345"}}},"required":["amount"]},"PayUsingSavedCardResponseDto":{"type":"object","properties":{"pm_id":{"type":"string","description":"Payment method ID (card ID)","example":"pm_xxxxxxxxxxxxx"},"client_secret":{"type":"string","nullable":true,"description":"Client secret for confirming payment (if authentication required)","example":"pi_xxxxxxxxxxxxx_secret_xxxxxxxxxxxxx"},"status":{"type":"string","description":"Payment intent status","example":"succeeded","enum":["requires_payment_method","requires_confirmation","requires_action","processing","requires_capture","canceled","succeeded"]},"payment_intent_id":{"type":"string","description":"Payment intent ID","example":"pi_xxxxxxxxxxxxx"}},"required":["pm_id"]},"TopUpUsingSavedCardDto":{"type":"object","properties":{"amount":{"type":"number","minimum":0.01,"description":"Amount in DOLLARS (e.g., 10 = $10.00, 55.50 = $55.50). Backend will convert to cents for Stripe.","example":10},"currency":{"type":"string","default":"usd","description":"Currency code","example":"usd"},"metadata":{"type":"object","description":"Optional metadata","example":{"orderId":"12345"}}},"required":["amount"]},"TopUpUsingSavedCardResponseDto":{"type":"object","properties":{"pm_id":{"type":"string","description":"Payment method ID (card ID)","example":"pm_xxxxxxxxxxxxx"},"client_secret":{"type":"string","nullable":true,"description":"Client secret for confirming payment (if authentication required)","example":"pi_xxxxxxxxxxxxx_secret_xxxxxxxxxxxxx"},"status":{"type":"string","description":"Payment intent status","example":"succeeded","enum":["requires_payment_method","requires_confirmation","requires_action","processing","requires_capture","canceled","succeeded"]},"payment_intent_id":{"type":"string","description":"Payment intent ID","example":"pi_xxxxxxxxxxxxx"}},"required":["pm_id"]},"ActiveCardInfoDto":{"type":"object","properties":{"customer_id":{"type":"string","description":"Stripe customer ID","example":"cus_xxxxxxxxxxxxx"},"pm_id":{"type":"string","description":"Payment method ID","example":"pm_xxxxxxxxxxxxx"},"brand":{"type":"string","description":"Card brand","example":"visa"},"country":{"type":"string","nullable":true,"description":"Two-letter ISO country code","example":"US"},"exp_month":{"type":"number","description":"Card expiration month","example":12},"exp_year":{"type":"number","description":"Card expiration year","example":2025},"funding":{"type":"string","description":"Card funding type","example":"credit","enum":["credit","debit","prepaid","unknown"]},"last4":{"type":"string","description":"Last 4 digits of the card","example":"4242"},"address_line_1_check":{"type":"string","nullable":true,"description":"Address line 1 check result","example":"pass","enum":["pass","fail","unavailable","unchecked"]},"address_postal_code_check":{"type":"string","nullable":true,"description":"Postal code check result","example":"pass","enum":["pass","fail","unavailable","unchecked"]},"cvc_check":{"type":"string","nullable":true,"description":"CVC check result","example":"pass","enum":["pass","fail","unavailable","unchecked"]}},"required":["customer_id","pm_id"]},"WebhookResponseDto":{"type":"object","properties":{"received":{"type":"boolean","description":"Indicates webhook was received successfully","example":true}},"required":["received"]},"CreateTicketDto":{"type":"object","properties":{"subject":{"type":"string","maxLength":200,"description":"Ticket subject/title","example":"Proxy connection timeout"},"message":{"type":"string","maxLength":5000,"description":"Detailed description of the issue","example":"Getting timeout errors on my US proxy since this morning"},"priority":{"default":"medium","enum":["low","medium","high","urgent"],"type":"string","description":"Ticket priority level"},"category":{"default":"general","enum":["technical","billing","general","feature_request","port_issue","port_addition_request"],"type":"string","description":"Ticket category"},"relatedPortIds":{"description":"IDs of related ports experiencing issues","example":["6728abc123def456","6728abc123def789"],"type":"array","items":{"type":"string"}}},"required":["subject","message"]},"UserSummaryDto":{"type":"object","properties":{"_id":{"type":"string"},"email":{"type":"string"},"name":{"type":"string"}},"required":["_id","email"]},"PortSummaryDto":{"type":"object","properties":{"_id":{"type":"string"},"name":{"type":"string"},"serverIp":{"type":"string"},"httpPort":{"type":"number"},"socksPort":{"type":"number"}},"required":["_id","name","serverIp","httpPort","socksPort"]},"TicketReplyResponseDto":{"type":"object","properties":{"_id":{"type":"string"},"ticketId":{"type":"string"},"message":{"type":"string"},"authorType":{"enum":["customer","support"],"type":"string"},"author":{"$ref":"#/components/schemas/UserSummaryDto"},"isInternal":{"type":"boolean"},"createdAt":{"type":"number"}},"required":["_id","ticketId","message","authorType","author","isInternal","createdAt"]},"TicketResponseDto":{"type":"object","properties":{"_id":{"type":"string"},"ticketNumber":{"type":"string","example":"TKT-20251129-001"},"subject":{"type":"string"},"message":{"type":"string"},"status":{"enum":["open","in_progress","waiting_customer","resolved","closed"],"type":"string"},"priority":{"enum":["low","medium","high","urgent"],"type":"string"},"category":{"enum":["technical","billing","general","feature_request","port_issue","port_addition_request"],"type":"string"},"user":{"$ref":"#/components/schemas/UserSummaryDto"},"relatedPorts":{"type":"array","items":{"$ref":"#/components/schemas/PortSummaryDto"}},"assignedTo":{"$ref":"#/components/schemas/UserSummaryDto"},"replies":{"type":"array","items":{"$ref":"#/components/schemas/TicketReplyResponseDto"}},"repliesCount":{"type":"number"},"createdAt":{"type":"number"},"updatedAt":{"type":"number"}},"required":["_id","ticketNumber","subject","message","status","priority","category","user","createdAt","updatedAt"]},"CreateReplyDto":{"type":"object","properties":{"message":{"type":"string","maxLength":10000,"description":"Reply message content","example":"Thank you for reporting. We are investigating the issue."},"isInternal":{"type":"boolean","default":false,"description":"Mark as internal note (admin only, not visible to customer)"},"sendEmail":{"type":"boolean","default":false,"description":"Send email notification to customer about this reply"}},"required":["message"]},"TicketListResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/TicketResponseDto"}},"total":{"type":"number"},"page":{"type":"number"},"limit":{"type":"number"},"totalPages":{"type":"number"}},"required":["data","total","page","limit","totalPages"]},"UpdateTicketDto":{"type":"object","properties":{"status":{"enum":["open","in_progress","waiting_customer","resolved","closed"],"type":"string","description":"Update ticket status"},"priority":{"enum":["low","medium","high","urgent"],"type":"string","description":"Update ticket priority"},"category":{"enum":["technical","billing","general","feature_request","port_issue","port_addition_request"],"type":"string","description":"Update ticket category"},"assignedToId":{"type":"string","description":"Assign ticket to an admin user ID","example":"69276bf1f547dfc948699200"},"subject":{"type":"string","maxLength":200,"description":"Update ticket subject (admin only)"}}},"CreateCouponDto":{"type":"object","properties":{"code":{"type":"string","minLength":3,"maxLength":20,"pattern":"/^[A-Za-z0-9]+$/","example":"SAVE20","description":"Unique coupon code (auto-uppercase)"},"name":{"type":"string","minLength":3,"maxLength":100,"example":"20% Off Summer Sale","description":"Admin-friendly name"},"description":{"type":"string","maxLength":500,"example":"Get 20% off your purchase","description":"Optional description"},"type":{"enum":["percentage","fixed_amount","free_traffic","free_ports"],"type":"string","example":"percentage"},"value":{"type":"number","minimum":0,"maximum":100000,"example":20,"description":"Discount value (20 for 20%, 10 for $10, etc.)"},"usageType":{"enum":["single_use","multi_use","limited_use","one_per_user","limited_per_user"],"type":"string","example":"multi_use"},"maxTotalUses":{"type":"number","minimum":1,"example":100,"description":"Max total uses for LIMITED_USE type"},"maxUsesPerUser":{"type":"number","minimum":1,"example":3,"description":"Max uses per user for LIMITED_PER_USER type"},"validFrom":{"format":"date-time","type":"string","example":"2024-12-01T00:00:00Z","description":"Start date of validity"},"validUntil":{"format":"date-time","type":"string","example":"2024-12-31T23:59:59Z","description":"End date of validity"},"minOrderAmount":{"type":"number","minimum":0,"example":50,"description":"Minimum order amount to apply coupon"},"maxDiscountAmount":{"type":"number","minimum":0,"example":100,"description":"Maximum discount amount (for percentage coupons)"},"applicableTo":{"example":["traffic","ports"],"description":"What this coupon applies to","type":"array","items":{"type":"string"}},"restrictedToUsers":{"example":[],"description":"Restrict to specific user IDs","type":"array","items":{"type":"string"}},"firstPurchaseOnly":{"type":"boolean","example":false,"description":"Only for first-time customers"}},"required":["code","name","type","value","usageType","validFrom","validUntil"]},"UpdateCouponDto":{"type":"object","properties":{"code":{"type":"string","minLength":3,"maxLength":20,"pattern":"/^[A-Za-z0-9]+$/","example":"SAVE20","description":"Unique coupon code (auto-uppercase)"},"name":{"type":"string","minLength":3,"maxLength":100,"example":"20% Off Summer Sale","description":"Admin-friendly name"},"description":{"type":"string","maxLength":500,"example":"Get 20% off your purchase","description":"Optional description"},"type":{"enum":["percentage","fixed_amount","free_traffic","free_ports"],"type":"string","example":"percentage"},"value":{"type":"number","minimum":0,"maximum":100000,"example":20,"description":"Discount value (20 for 20%, 10 for $10, etc.)"},"usageType":{"enum":["single_use","multi_use","limited_use","one_per_user","limited_per_user"],"type":"string","example":"multi_use"},"maxTotalUses":{"type":"number","minimum":1,"example":100,"description":"Max total uses for LIMITED_USE type"},"maxUsesPerUser":{"type":"number","minimum":1,"example":3,"description":"Max uses per user for LIMITED_PER_USER type"},"validFrom":{"format":"date-time","type":"string","example":"2024-12-01T00:00:00Z","description":"Start date of validity"},"validUntil":{"format":"date-time","type":"string","example":"2024-12-31T23:59:59Z","description":"End date of validity"},"minOrderAmount":{"type":"number","minimum":0,"example":50,"description":"Minimum order amount to apply coupon"},"maxDiscountAmount":{"type":"number","minimum":0,"example":100,"description":"Maximum discount amount (for percentage coupons)"},"applicableTo":{"example":["traffic","ports"],"description":"What this coupon applies to","type":"array","items":{"type":"string"}},"restrictedToUsers":{"example":[],"description":"Restrict to specific user IDs","type":"array","items":{"type":"string"}},"firstPurchaseOnly":{"type":"boolean","example":false,"description":"Only for first-time customers"},"status":{"enum":["active","inactive","expired"],"type":"string","example":"active"}}},"ValidateCouponDto":{"type":"object","properties":{"code":{"type":"string","minLength":3,"maxLength":20,"pattern":"/^[A-Za-z0-9]+$/","example":"SAVE20","description":"Coupon code to validate"},"orderAmount":{"type":"number","minimum":0,"example":200,"description":"Order amount to validate against"},"orderType":{"type":"string","enum":["traffic","ports","all"],"example":"traffic"}},"required":["code","orderAmount","orderType"]},"AddRecipientDto":{"type":"object","properties":{"email":{"type":"string"},"label":{"type":"string"},"notifyNewSignup":{"type":"boolean"},"notifyNewPurchase":{"type":"boolean"},"notifyNewTopup":{"type":"boolean"},"notifyNewTicket":{"type":"boolean"},"notifyTicketReply":{"type":"boolean"}},"required":["email"]},"UpdateSettingsDto":{"type":"object","properties":{"isActive":{"type":"boolean"},"label":{"type":"string"},"notifyNewSignup":{"type":"boolean"},"notifyNewPurchase":{"type":"boolean"},"notifyNewTopup":{"type":"boolean"},"notifyNewTicket":{"type":"boolean"},"notifyTicketReply":{"type":"boolean"}}},"DeviceEarningDto":{"type":"object","properties":{"deviceId":{"type":"string"},"deviceImei":{"type":"string"},"deviceName":{"type":"string"},"isPrivate":{"type":"boolean"},"trafficInMB":{"type":"number"},"trafficOutMB":{"type":"number"},"totalTrafficMB":{"type":"number"},"ratePerMB":{"type":"number"},"grossEarnings":{"type":"number"}},"required":["deviceId","deviceImei","deviceName","isPrivate","trafficInMB","trafficOutMB","totalTrafficMB","ratePerMB","grossEarnings"]},"FarmerEarningsResponseDto":{"type":"object","properties":{"id":{"type":"string"},"farmerId":{"type":"string"},"periodStart":{"type":"number"},"periodEnd":{"type":"number"},"periodLabel":{"type":"string"},"devices":{"type":"array","items":{"$ref":"#/components/schemas/DeviceEarningDto"}},"totalDevices":{"type":"number"},"totalTrafficMB":{"type":"number"},"totalTrafficGB":{"type":"number"},"sharedTrafficMB":{"type":"number"},"privateTrafficMB":{"type":"number"},"grossEarnings":{"type":"number"},"platformFeePercent":{"type":"number"},"platformFee":{"type":"number"},"netEarnings":{"type":"number"},"status":{"enum":["calculated","approved","paid","disputed"],"type":"string"},"approvedAt":{"type":"number"},"paidAt":{"type":"number"},"createdAt":{"type":"number"}},"required":["id","farmerId","periodStart","periodEnd","periodLabel","devices","totalDevices","totalTrafficMB","totalTrafficGB","sharedTrafficMB","privateTrafficMB","grossEarnings","platformFeePercent","platformFee","netEarnings","status","createdAt"]},"EarningsSummaryDto":{"type":"object","properties":{"totalEarnings":{"type":"number","description":"Total earnings across all periods"},"pendingEarnings":{"type":"number","description":"Pending (unpaid) earnings"},"paidEarnings":{"type":"number","description":"Total paid out"},"currentMonthEarnings":{"type":"number","description":"Current month earnings"},"lastMonthEarnings":{"type":"number","description":"Last month earnings"},"totalTrafficMB":{"type":"number","description":"Total traffic generated (MB)"},"currentMonthTrafficMB":{"type":"number","description":"Current month traffic (MB)"},"lastMonthTrafficMB":{"type":"number","description":"Last month traffic (MB)"},"allTimeNetEarnings":{"type":"number","description":"All time net earnings"},"pendingApproval":{"type":"number","description":"Pending approval amount"},"totalPaidOut":{"type":"number","description":"Total paid out"},"allTimeTrafficMB":{"type":"number","description":"All time traffic (MB)"},"activeDevices":{"type":"number","description":"Active devices count"},"avgEarningsPerDevice":{"type":"number","description":"Average earnings per device"}},"required":["totalEarnings","pendingEarnings","paidEarnings","currentMonthEarnings","lastMonthEarnings","totalTrafficMB","currentMonthTrafficMB","lastMonthTrafficMB","allTimeNetEarnings","pendingApproval","totalPaidOut","allTimeTrafficMB","activeDevices","avgEarningsPerDevice"]},"CalculateEarningsDto":{"type":"object","properties":{"periodStart":{"type":"number","description":"Period start timestamp"},"periodEnd":{"type":"number","description":"Period end timestamp"},"farmerId":{"type":"string","description":"Specific farmer ID (admin only, calculates for all if omitted)"}},"required":["periodStart","periodEnd"]},"ApproveEarningsDto":{"type":"object","properties":{"notes":{"type":"string","description":"Admin notes"}}},"FarmerPayoutResponseDto":{"type":"object","properties":{"id":{"type":"string"},"farmerId":{"type":"string"},"earningsIds":{"type":"array","items":{"type":"string"}},"amount":{"type":"number"},"currency":{"type":"string"},"method":{"enum":["bank_transfer","usdt_trc20","usdt_erc20","paypal","wise"],"type":"string"},"status":{"enum":["pending","processing","completed","failed","cancelled"],"type":"string"},"transactionId":{"type":"string"},"transactionHash":{"type":"string"},"processedAt":{"type":"number"},"completedAt":{"type":"number"},"failedAt":{"type":"number"},"failureReason":{"type":"string"},"farmerNotes":{"type":"string"},"createdAt":{"type":"number"}},"required":["id","farmerId","earningsIds","amount","currency","method","status","createdAt"]},"PayoutSummaryDto":{"type":"object","properties":{"totalPaid":{"type":"number","description":"Total amount paid out"},"pendingAmount":{"type":"number","description":"Pending payout amount"},"successfulPayouts":{"type":"number","description":"Number of successful payouts"},"pendingPayouts":{"type":"number","description":"Number of pending payouts"},"lastPayoutDate":{"type":"number","description":"Last payout date"},"lastPayoutAmount":{"type":"number","description":"Last payout amount"}},"required":["totalPaid","pendingAmount","successfulPayouts","pendingPayouts"]},"RequestPayoutDto":{"type":"object","properties":{"currency":{"type":"string","enum":["usdt","btc","sol","paypal"],"example":"usdt","description":"Payout currency/method"}},"required":["currency"]},"ProcessPayoutDto":{"type":"object","properties":{"transactionId":{"type":"string","description":"Transaction ID from payment processor"},"transactionHash":{"type":"string","description":"Transaction hash (for crypto)"},"adminNotes":{"type":"string","description":"Admin notes"}},"required":["transactionId"]},"FailPayoutDto":{"type":"object","properties":{"reason":{"type":"string","description":"Reason for failure"},"adminNotes":{"type":"string","description":"Admin notes"}},"required":["reason"]},"BankDetailsDto":{"type":"object","properties":{"accountName":{"type":"string","description":"Account holder name"},"bankName":{"type":"string","description":"Bank name"},"accountNumber":{"type":"string","description":"Account number"},"routingNumber":{"type":"string","description":"Routing number (US banks)"},"swiftCode":{"type":"string","description":"SWIFT/BIC code (international)"},"iban":{"type":"string","description":"IBAN (European banks)"},"country":{"type":"string","description":"Country"}},"required":["accountName","bankName","accountNumber","country"]},"FarmerSettingsResponseDto":{"type":"object","properties":{"farmerId":{"type":"string"},"preferredPayoutMethod":{"enum":["bank_transfer","usdt_trc20","usdt_erc20","paypal","wise"],"type":"string"},"bankDetails":{"$ref":"#/components/schemas/BankDetailsDto"},"usdtTrc20Address":{"type":"string"},"usdtErc20Address":{"type":"string"},"paypalEmail":{"type":"string"},"wiseEmail":{"type":"string"},"minimumPayoutAmount":{"type":"number"},"autoRequestPayout":{"type":"boolean"},"emailOnEarningsCalculated":{"type":"boolean"},"emailOnPayoutProcessed":{"type":"boolean"},"taxId":{"type":"string"},"businessName":{"type":"string"},"businessAddress":{"type":"string"},"effectiveSharedRatePerMB":{"type":"number","description":"Effective rate per MB for shared devices"},"effectivePrivateRatePerMB":{"type":"number","description":"Effective rate per MB for private devices"},"effectivePlatformFeePercent":{"type":"number","description":"Effective platform fee percent"}},"required":["farmerId","preferredPayoutMethod","minimumPayoutAmount","autoRequestPayout","emailOnEarningsCalculated","emailOnPayoutProcessed","effectiveSharedRatePerMB","effectivePrivateRatePerMB","effectivePlatformFeePercent"]},"UpdateFarmerSettingsDto":{"type":"object","properties":{"preferredPayoutMethod":{"enum":["bank_transfer","usdt_trc20","usdt_erc20","paypal","wise"],"type":"string","description":"Preferred payout method"},"bankDetails":{"description":"Bank details for bank transfers","allOf":[{"$ref":"#/components/schemas/BankDetailsDto"}]},"usdtTrc20Address":{"type":"string","description":"USDT TRC20 wallet address"},"usdtErc20Address":{"type":"string","description":"USDT ERC20 wallet address"},"paypalEmail":{"type":"string","format":"email","description":"PayPal email address"},"wiseEmail":{"type":"string","format":"email","description":"Wise email address"},"minimumPayoutAmount":{"type":"number","minimum":10,"maximum":1000,"description":"Minimum payout amount (USD)"},"autoRequestPayout":{"type":"boolean","description":"Auto-request payout when above minimum"},"emailOnEarningsCalculated":{"type":"boolean","description":"Receive email when earnings are calculated"},"emailOnPayoutProcessed":{"type":"boolean","description":"Receive email when payout is processed"},"taxId":{"type":"string","description":"Tax ID (VAT, EIN, etc.)"},"businessName":{"type":"string","description":"Business name for invoicing"},"businessAddress":{"type":"string","description":"Business address for invoicing"}}},"AdminUpdateFarmerSettingsDto":{"type":"object","properties":{"preferredPayoutMethod":{"enum":["bank_transfer","usdt_trc20","usdt_erc20","paypal","wise"],"type":"string","description":"Preferred payout method"},"bankDetails":{"description":"Bank details for bank transfers","allOf":[{"$ref":"#/components/schemas/BankDetailsDto"}]},"usdtTrc20Address":{"type":"string","description":"USDT TRC20 wallet address"},"usdtErc20Address":{"type":"string","description":"USDT ERC20 wallet address"},"paypalEmail":{"type":"string","format":"email","description":"PayPal email address"},"wiseEmail":{"type":"string","format":"email","description":"Wise email address"},"minimumPayoutAmount":{"type":"number","minimum":10,"maximum":1000,"description":"Minimum payout amount (USD)"},"autoRequestPayout":{"type":"boolean","description":"Auto-request payout when above minimum"},"emailOnEarningsCalculated":{"type":"boolean","description":"Receive email when earnings are calculated"},"emailOnPayoutProcessed":{"type":"boolean","description":"Receive email when payout is processed"},"taxId":{"type":"string","description":"Tax ID (VAT, EIN, etc.)"},"businessName":{"type":"string","description":"Business name for invoicing"},"businessAddress":{"type":"string","description":"Business address for invoicing"},"customSharedRatePerMB":{"type":"number","minimum":0,"description":"Custom rate per MB for shared devices (admin only)"},"customPrivateRatePerMB":{"type":"number","minimum":0,"description":"Custom rate per MB for private devices (admin only)"},"customPlatformFeePercent":{"type":"number","minimum":0,"maximum":100,"description":"Custom platform fee percent (admin only)"}}},"CreateCampaignDto":{"type":"object","properties":{"name":{"type":"string"},"description":{"type":"string"},"triggerType":{"enum":["after_signup_2h","after_signup_24h","after_signup_3d","after_signup_7d","no_purchase_24h","no_purchase_3d","no_purchase_7d","after_first_purchase","after_purchase","inactive_7d","inactive_14d","inactive_30d","port_expiring_24h","port_expiring_3d","port_expired","low_balance","high_engagement_no_purchase","at_risk_of_churn","approaching_milestone","multiple_ports_expiring","heavy_rotation_user","lead_grade_change","lifecycle_stage_change","manual","welcome"],"type":"string"},"subject":{"type":"string"},"htmlContent":{"type":"string"},"textContent":{"type":"string"},"status":{"enum":["active","paused","draft","archived"],"type":"string"},"delayMinutes":{"type":"number"},"conditions":{"type":"object","properties":{"minBalance":{"type":"number"},"maxBalance":{"type":"number"},"hasActivePorts":{"type":"boolean"},"hasPurchased":{"type":"boolean"}},"required":[]},"priority":{"type":"number"}},"required":["name","triggerType","subject","htmlContent"]},"UpdateCampaignDto":{"type":"object","properties":{"name":{"type":"string"},"description":{"type":"string"},"subject":{"type":"string"},"htmlContent":{"type":"string"},"textContent":{"type":"string"},"status":{"enum":["active","paused","draft","archived"],"type":"string"},"delayMinutes":{"type":"number"},"conditions":{"type":"object"},"priority":{"type":"number"}}},"BroadcastDto":{"type":"object","properties":{"campaignId":{"type":"string"},"userIds":{"type":"array","items":{"type":"string"}},"filters":{"type":"object","properties":{"hasActivePorts":{"type":"boolean"},"hasPurchased":{"type":"boolean"},"minBalance":{"type":"number"},"maxBalance":{"type":"number"},"registeredAfter":{"type":"string"},"registeredBefore":{"type":"string"}},"required":[]}},"required":["campaignId"]},"ScheduleEmailDto":{"type":"object","properties":{"userId":{"type":"string"},"triggerType":{"enum":["after_signup_2h","after_signup_24h","after_signup_3d","after_signup_7d","no_purchase_24h","no_purchase_3d","no_purchase_7d","after_first_purchase","after_purchase","inactive_7d","inactive_14d","inactive_30d","port_expiring_24h","port_expiring_3d","port_expired","low_balance","high_engagement_no_purchase","at_risk_of_churn","approaching_milestone","multiple_ports_expiring","heavy_rotation_user","lead_grade_change","lifecycle_stage_change","manual","welcome"],"type":"string"},"delayMinutes":{"type":"number"}},"required":["userId","triggerType"]},"TierPricing":{"type":"object","properties":{"tier":{"type":"string","description":"Tier name","example":"shared"},"portPriceMonthly":{"type":"number","description":"Port/slot is FREE - no time-based cost (USDC)","example":0},"trafficPricePerGB":{"type":"number","description":"Traffic price per GB (USDC)","example":4},"portPricePerHour":{"type":"number","description":"Port/slot is FREE - no time-based cost (USDC/hour)","example":0},"portPricePerDay":{"type":"number","description":"Port/slot is FREE - no time-based cost (USDC/day)","example":0}},"required":["tier","portPriceMonthly","trafficPricePerGB","portPricePerHour","portPricePerDay"]},"NetworkConfig":{"type":"object","properties":{"network":{"type":"string","description":"Network identifier","example":"base"},"chainId":{"type":"string","description":"CAIP-2 chain ID","example":"eip155:8453"},"enabled":{"type":"boolean","description":"Whether network is enabled","example":true},"usdcAddress":{"type":"string","description":"USDC token address","example":"0x833589fcd6edb6e08f4c7c32d4f71b54bda02913"},"recipientAddress":{"type":"string","description":"Recipient wallet address","example":"0x..."}},"required":["network","chainId","enabled","usdcAddress","recipientAddress"]},"X402PricingResponse":{"type":"object","properties":{"shared":{"description":"Shared tier pricing","allOf":[{"$ref":"#/components/schemas/TierPricing"}]},"private":{"description":"Private tier pricing","allOf":[{"$ref":"#/components/schemas/TierPricing"}]},"networks":{"description":"Supported networks","type":"array","items":{"$ref":"#/components/schemas/NetworkConfig"}},"minDurationSeconds":{"type":"number","description":"Minimum duration in seconds","example":3600},"maxDurationSeconds":{"type":"number","description":"Maximum duration in seconds","example":2592000},"minTrafficGB":{"type":"number","description":"Minimum traffic in GB","example":0.1}},"required":["shared","private","networks","minDurationSeconds","maxDurationSeconds","minTrafficGB"]},"CalculateCostResponse":{"type":"object","properties":{"portCost":{"type":"number","description":"Port cost in USDC (always 0.0 - ports are FREE)","example":0},"trafficCost":{"type":"number","description":"Traffic cost in USDC","example":4},"totalCost":{"type":"number","description":"Total cost in USDC (equals trafficCost)","example":4},"totalCostMicro":{"type":"string","description":"Total cost in USDC micro-units (6 decimals)","example":"4100000"},"breakdown":{"type":"object","properties":{"tier":{"type":"string"},"durationSeconds":{"type":"number"},"durationDisplay":{"type":"string"},"trafficGB":{"type":"number"},"portPricePerSecond":{"type":"number"},"trafficPricePerGB":{"type":"number"}},"required":["tier","durationSeconds","durationDisplay","trafficGB","portPricePerSecond","trafficPricePerGB"]}},"required":["portCost","trafficCost","totalCost","totalCostMicro","breakdown"]},"ProxyCredentials":{"type":"object","properties":{"http":{"type":"string","description":"HTTP proxy URL","example":"http://user_abc123:pass456@192.168.1.100:8045"},"socks5":{"type":"string","description":"SOCKS5 proxy URL","example":"socks5://user_abc123:pass456@192.168.1.100:5045"},"server":{"type":"string","description":"Server IP address","example":"192.168.1.100"},"httpPort":{"type":"number","description":"HTTP port number","example":8045},"socksPort":{"type":"number","description":"SOCKS5 port number","example":5045},"username":{"type":"string","description":"Proxy username","example":"user_abc123"},"password":{"type":"string","description":"Proxy password","example":"pass456"},"expiresAt":{"type":"string","description":"Port expiration timestamp (ISO 8601)","example":"2024-12-31T23:59:59.000Z"}},"required":["http","socks5","server","httpPort","socksPort","username","password","expiresAt"]},"TrafficInfo":{"type":"object","properties":{"allocatedGB":{"type":"number","description":"Total traffic allocated in GB","example":1},"usedGB":{"type":"number","description":"Traffic used in GB","example":0},"remainingGB":{"type":"number","description":"Traffic remaining in GB","example":1}},"required":["allocatedGB","usedGB","remainingGB"]},"PaymentInfo":{"type":"object","properties":{"txHash":{"type":"string","description":"Transaction hash","example":"0x..."},"network":{"type":"string","description":"Network used","example":"base"},"amountUSDC":{"type":"number","description":"Amount paid in USDC","example":4.1},"walletAddress":{"type":"string","description":"Payer wallet address","example":"0x..."}},"required":["txHash","network","amountUSDC","walletAddress"]},"ManagementInfo":{"type":"object","properties":{"sessionToken":{"type":"string","description":"Session token for authenticated management endpoints","example":"x402s_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6"},"statusEndpoint":{"type":"string","description":"Endpoint to check port status","example":"GET https://api.proxies.sx/v1/x402/manage/ports/:portId/status"},"sessionEndpoint":{"type":"string","description":"Endpoint to check session and traffic","example":"GET https://api.proxies.sx/v1/x402/manage/session"},"replaceEndpoint":{"type":"string","description":"Endpoint to replace offline port (free, max 3)","example":"POST https://api.proxies.sx/v1/x402/manage/ports/replace"},"topupEndpoint":{"type":"string","description":"Endpoint to top up session with more traffic/duration","example":"POST https://api.proxies.sx/v1/x402/manage/session/topup"},"authMethod":{"type":"string","description":"How to authenticate with session token","example":"Header: X-Session-Token: x402s_..."}},"required":["sessionToken","statusEndpoint","sessionEndpoint","authMethod"]},"X402ProxyResponse":{"type":"object","properties":{"proxy":{"description":"Proxy credentials","allOf":[{"$ref":"#/components/schemas/ProxyCredentials"}]},"rotationUrl":{"type":"string","description":"Public rotation URL (no auth required)","example":"https://api.proxies.sx/rotate/abc123def456..."},"sessionId":{"type":"string","description":"Session ID for tracking","example":"507f1f77bcf86cd799439011"},"portId":{"type":"string","description":"Port ID","example":"507f1f77bcf86cd799439012"},"traffic":{"description":"Traffic allocation info","allOf":[{"$ref":"#/components/schemas/TrafficInfo"}]},"payment":{"description":"Payment info","allOf":[{"$ref":"#/components/schemas/PaymentInfo"}]},"location":{"type":"object","properties":{"country":{"type":"string"},"countryCode":{"type":"string"},"city":{"type":"string"},"carrier":{"type":"string"}},"required":["country","countryCode"]},"management":{"description":"Management info for post-purchase operations","allOf":[{"$ref":"#/components/schemas/ManagementInfo"}]}},"required":["proxy","rotationUrl","sessionId","portId","traffic","payment","location","management"]},"X402ProxyRequestDto":{"type":"object","properties":{"country":{"type":"string","description":"Country code (ISO 3166-1 alpha-2) or country MongoDB ID","example":"US"},"city":{"type":"string","description":"City code or MongoDB ID (optional)","example":"NYC"},"carrier":{"type":"string","description":"Carrier code or MongoDB ID (optional)","example":"verizon"},"duration":{"type":"number","minimum":3600,"maximum":2592000,"description":"Duration in seconds (min: 3600, max: 2592000)","example":86400},"traffic":{"type":"number","minimum":0.1,"description":"Traffic allocation in GB (min: 0.1)","example":1},"tier":{"type":"string","description":"Tier: shared (default) or private","example":"shared","enum":["shared","private"]},"network":{"type":"string","description":"Preferred network for payment (base or solana)","example":"base","enum":["base","solana"]}},"required":["country","duration","traffic"]},"X402SessionResponse":{"type":"object","properties":{"sessionId":{"type":"string","description":"Session ID","example":"507f1f77bcf86cd799439011"},"walletAddress":{"type":"string","description":"Wallet address","example":"0x..."},"network":{"type":"string","description":"Network used","example":"base"},"txHash":{"type":"string","description":"Transaction hash","example":"0x..."},"amountUSDC":{"type":"number","description":"Amount paid in USDC","example":4.1},"tier":{"type":"string","description":"Tier","example":"shared"},"trafficAllocatedGB":{"type":"number","description":"Traffic allocated in GB","example":1},"trafficUsedGB":{"type":"number","description":"Traffic used in GB","example":0.5},"portCount":{"type":"number","description":"Number of ports","example":1},"expiresAt":{"type":"string","description":"Session expiration","example":"2024-12-31T23:59:59.000Z"},"isActive":{"type":"boolean","description":"Whether session is active","example":true},"createdAt":{"type":"string","description":"Session creation time","example":"2024-12-01T00:00:00.000Z"}},"required":["sessionId","walletAddress","network","txHash","amountUSDC","tier","trafficAllocatedGB","trafficUsedGB","portCount","expiresAt","isActive","createdAt"]},"X402ReplacePortDto":{"type":"object","properties":{"portId":{"type":"string","description":"Port ID to replace (optional - defaults to first offline port in session)"},"country":{"type":"string","description":"Country code for new port (optional - defaults to same country)"},"city":{"type":"string","description":"City code for new port (optional)"},"carrier":{"type":"string","description":"Carrier code for new port (optional)"}}},"X402TopupDto":{"type":"object","properties":{"addTrafficGB":{"type":"number","minimum":0.1,"description":"Additional traffic in GB (minimum 0.1)","example":1},"addDurationSeconds":{"type":"number","minimum":3600,"description":"Additional duration in seconds (minimum 3600 = 1 hour)","example":86400}}},"X402AgentResponse":{"type":"object","properties":{"walletAddress":{"type":"string"},"name":{"type":"string"},"network":{"type":"string"},"description":{"type":"string"},"contactEmail":{"type":"string"},"website":{"type":"string"},"registeredBy":{"type":"string"},"isActive":{"type":"boolean"},"totalSessions":{"type":"number"},"totalSpentUSDC":{"type":"number"},"lastSeenAt":{"type":"string"},"createdAt":{"type":"string"}},"required":["walletAddress","name","network","registeredBy","isActive","totalSessions","totalSpentUSDC","createdAt"]},"X402AgentListResponse":{"type":"object","properties":{"agents":{"type":"array","items":{"$ref":"#/components/schemas/X402AgentResponse"}},"total":{"type":"number"},"page":{"type":"number"},"limit":{"type":"number"},"totalPages":{"type":"number"}},"required":["agents","total","page","limit","totalPages"]},"RegisterAgentDto":{"type":"object","properties":{"name":{"type":"string","minLength":3,"maxLength":64,"pattern":"/^[a-zA-Z0-9_-]+$/","description":"Human-readable name for the agent (alphanumeric, hyphens, underscores)","example":"maya-bandwidth-agent"},"type":{"type":"string","enum":["claude","gpt","custom"],"description":"Type of AI agent","example":"claude"},"walletAddress":{"type":"string","minLength":32,"maxLength":44,"pattern":"/^[1-9A-HJ-NP-Za-km-z]+$/","description":"Solana wallet address for USDC payouts (32-44 base58 characters)","example":"6eUdVwsPArTxwVqEARYGCh4S2qwW2zCs7jSEDRpxydnv"},"apiKey":{"type":"string","description":"API key (psx_...) to auto-link this agent to your farmer account","example":"psx_396ce4f83e1bc192c334a6bc2702949f"}},"required":["name","type"]},"UpdateAgentDto":{"type":"object","properties":{"name":{"type":"string","minLength":2,"maxLength":100,"description":"Human-readable agent name","example":"Customer XYZ Bot"},"description":{"type":"string","maxLength":500,"description":"Description of the agent"},"contactEmail":{"type":"string","format":"email","description":"Contact email for support"},"website":{"type":"string","format":"uri","description":"Website or documentation URL"},"isActive":{"type":"boolean","description":"Whether the agent is active"},"metadata":{"type":"object","description":"Additional metadata"}}},"X402SessionListItem":{"type":"object","properties":{"id":{"type":"string"},"walletAddress":{"type":"string"},"agentName":{"type":"string","description":"Agent name from registry"},"network":{"type":"string"},"txHash":{"type":"string"},"amountUSDC":{"type":"number"},"tier":{"type":"string"},"portsCount":{"type":"number"},"trafficAllocatedGB":{"type":"number"},"trafficUsedGB":{"type":"number"},"expiresAt":{"type":"string"},"isActive":{"type":"boolean"},"createdAt":{"type":"string"}},"required":["id","walletAddress","network","txHash","amountUSDC","tier","portsCount","trafficAllocatedGB","trafficUsedGB","expiresAt","isActive","createdAt"]},"X402SessionListResponse":{"type":"object","properties":{"sessions":{"type":"array","items":{"$ref":"#/components/schemas/X402SessionListItem"}},"total":{"type":"number"},"page":{"type":"number"},"limit":{"type":"number"},"totalPages":{"type":"number"}},"required":["sessions","total","page","limit","totalPages"]},"X402StatsResponse":{"type":"object","properties":{"totalRevenue":{"type":"number"},"totalSessions":{"type":"number"},"activeSessions":{"type":"number"},"totalAgents":{"type":"number"},"totalPorts":{"type":"number"},"revenueByNetwork":{"type":"object","properties":{"base":{"type":"number"},"solana":{"type":"number"}},"required":["base","solana"]},"sessionsByTier":{"type":"object","properties":{"shared":{"type":"number"},"private":{"type":"number"}},"required":["shared","private"]}},"required":["totalRevenue","totalSessions","activeSessions","totalAgents","totalPorts","revenueByNetwork","sessionsByTier"]},"CreateCustomerDto":{"type":"object","properties":{"email":{"type":"string","format":"email","description":"Customer email address","example":"customer@example.com"},"name":{"type":"string","description":"Customer name","example":"John Doe"},"company":{"type":"string","description":"Company name","example":"Acme Corp"},"allocatedPortSlots":{"type":"number","minimum":0,"description":"Manual slot override (DEPRECATED - use tier system). Set to 0 to use automatic tier-based limits.","example":0,"default":0,"deprecated":true},"allocatedTrafficGB":{"type":"number","minimum":0,"description":"Allocated traffic in GB for this customer","example":100,"default":0},"externalId":{"type":"string","description":"External ID for integration with reseller systems","example":"cust_12345"},"metadata":{"type":"object","description":"Custom metadata for reseller use","example":{"salesRep":"John","tier":"premium"}},"notes":{"type":"string","description":"Internal notes about this customer","example":"High-volume customer, VIP support"},"canCreatePorts":{"type":"boolean","description":"Whether customer can create ports","default":true},"canRotatePorts":{"type":"boolean","description":"Whether customer can rotate ports","default":true},"initialBalance":{"type":"number","minimum":0,"description":"Initial balance to credit to the customer","example":100,"default":0}},"required":["email","name"]},"UpdateCustomerDto":{"type":"object","properties":{"email":{"type":"string","format":"email","description":"Customer email address","example":"customer@example.com"},"name":{"type":"string","description":"Customer name","example":"John Doe"},"company":{"type":"string","description":"Company name","example":"Acme Corp"},"allocatedPortSlots":{"type":"number","minimum":0,"description":"Allocated port slots for this customer","example":10},"allocatedTrafficGB":{"type":"number","minimum":0,"description":"Allocated traffic in GB for this customer","example":100},"externalId":{"type":"string","description":"External ID for integration with reseller systems","example":"cust_12345"},"metadata":{"type":"object","description":"Custom metadata for reseller use","example":{"salesRep":"John","tier":"premium"}},"notes":{"type":"string","description":"Internal notes about this customer","example":"High-volume customer, VIP support"},"canCreatePorts":{"type":"boolean","description":"Whether customer can create ports"},"canRotatePorts":{"type":"boolean","description":"Whether customer can rotate ports"}}},"SuspendCustomerDto":{"type":"object","properties":{"reason":{"type":"string","description":"Reason for suspending the customer","example":"Non-payment"}}},"TopupCustomerDto":{"type":"object","properties":{"amount":{"type":"number","minimum":0.01,"description":"Amount to add to customer balance","example":100},"trafficGB":{"type":"number","minimum":0,"description":"Traffic in GB being purchased (for tier progression)","example":50},"description":{"type":"string","description":"Description or reference for this topup","example":"Monthly credit allocation"},"referenceId":{"type":"string","description":"External reference ID (e.g., invoice number)","example":"INV-2026-001"}},"required":["amount"]},"AllocateQuotaDto":{"type":"object","properties":{"portSlots":{"type":"number","minimum":0,"description":"Number of port slots to allocate (replaces existing allocation)","example":20},"trafficGB":{"type":"number","minimum":0,"description":"Traffic quota in GB to allocate (replaces existing allocation)","example":100}}},"AdjustQuotaDto":{"type":"object","properties":{"portSlotsDelta":{"type":"number","description":"Port slots to add (positive) or remove (negative)","example":5},"trafficGBDelta":{"type":"number","description":"Traffic GB to add (positive) or remove (negative)","example":50},"reason":{"type":"string","description":"Reason for the adjustment","example":"Upgrade to premium plan"}}},"DeductBalanceDto":{"type":"object","properties":{"amount":{"type":"number","minimum":0.01,"description":"Amount to deduct from customer balance","example":50},"reason":{"type":"string","description":"Reason for the deduction","example":"Port purchase: Germany 30-day"},"referenceId":{"type":"string","description":"External reference ID (e.g., order number)","example":"ORD-2026-001"}},"required":["amount","reason"]},"RefundBalanceDto":{"type":"object","properties":{"amount":{"type":"number","minimum":0.01,"description":"Amount to refund from customer balance back to reseller","example":25},"reason":{"type":"string","description":"Reason for the refund","example":"Port cancellation refund"},"referenceId":{"type":"string","description":"External reference ID (e.g., refund ticket number)","example":"REF-2026-001"}},"required":["amount","reason"]},"AdjustBalanceDto":{"type":"object","properties":{"amount":{"type":"number","description":"Amount to adjust (positive = add, negative = deduct). Does NOT affect reseller balance.","example":-10},"reason":{"type":"string","description":"Reason for the adjustment","example":"Billing correction - overcharged on previous invoice"},"referenceId":{"type":"string","description":"External reference ID","example":"ADJ-2026-001"}},"required":["amount","reason"]},"PortPricingDto":{"type":"object","properties":{"marginPercent":{"type":"number","minimum":0,"maximum":500,"description":"Margin percentage to add to base price","example":25},"fixedPricePerDay":{"type":"number","minimum":0,"description":"Fixed price per day (overrides margin)","example":2.5},"multiplier":{"type":"number","minimum":1,"maximum":10,"description":"Multiplier to apply to base price","example":1.25},"minimumPrice":{"type":"number","minimum":0,"description":"Minimum price floor per day","example":1}}},"TrafficPricingDto":{"type":"object","properties":{"marginPercent":{"type":"number","minimum":0,"maximum":500,"description":"Margin percentage to add to base traffic price","example":30},"fixedPricePerGB":{"type":"number","minimum":0,"description":"Fixed price per GB (overrides margin)","example":0.75},"multiplier":{"type":"number","minimum":1,"maximum":10,"description":"Multiplier to apply to base traffic price","example":1.3},"minimumPricePerGB":{"type":"number","minimum":0,"description":"Minimum price floor per GB","example":0.5}}},"CountryOverrideDto":{"type":"object","properties":{"countryId":{"type":"string","description":"Country ID to override pricing for","example":"6574a1b2c3d4e5f6a7b8c9d0"},"portPricePerDay":{"type":"number","minimum":0,"description":"Fixed price per day for this country","example":5},"trafficPricePerGB":{"type":"number","minimum":0,"description":"Fixed price per GB for this country","example":1}},"required":["countryId"]},"CustomerOverrideDto":{"type":"object","properties":{"customerId":{"type":"string","description":"Customer ID to override pricing for","example":"6574a1b2c3d4e5f6a7b8c9d0"},"marginPercent":{"type":"number","minimum":0,"description":"Custom margin percentage for this customer","example":15},"discountPercent":{"type":"number","minimum":0,"maximum":100,"description":"Discount percentage off calculated price","example":10}},"required":["customerId"]},"UpdatePricebookDto":{"type":"object","properties":{"pricingMode":{"enum":["margin","fixed","multiplier"],"type":"string","description":"Pricing mode"},"portPricing":{"description":"Port pricing configuration","allOf":[{"$ref":"#/components/schemas/PortPricingDto"}]},"trafficPricing":{"description":"Traffic pricing configuration","allOf":[{"$ref":"#/components/schemas/TrafficPricingDto"}]},"countryOverrides":{"description":"Country-specific pricing overrides","type":"array","items":{"$ref":"#/components/schemas/CountryOverrideDto"}},"customerOverrides":{"description":"Customer-specific pricing overrides","type":"array","items":{"$ref":"#/components/schemas/CustomerOverrideDto"}},"defaultMarginPercent":{"type":"number","minimum":0,"maximum":500,"description":"Default margin percentage for new customers","example":20}}},"CalculatePriceDto":{"type":"object","properties":{"type":{"type":"string","description":"Type of purchase","enum":["port","traffic"]},"customerId":{"type":"string","description":"Customer ID for customer-specific pricing","example":"6574a1b2c3d4e5f6a7b8c9d0"},"countryId":{"type":"string","description":"Country ID for country-specific pricing","example":"6574a1b2c3d4e5f6a7b8c9d0"},"days":{"type":"number","minimum":1,"description":"Number of days (for port purchase)","example":30},"trafficGB":{"type":"number","minimum":1,"description":"Amount of traffic in GB (for traffic purchase)","example":10},"basePrice":{"type":"number","minimum":0,"description":"Base price from tariff (required for calculation)","example":2}},"required":["type"]},"CreateWebhookDto":{"type":"object","properties":{"name":{"type":"string","description":"Webhook name for identification","example":"My App Webhook"},"url":{"type":"string","format":"uri","description":"Webhook URL to receive events","example":"https://myapp.com/webhooks/proxies"},"events":{"minItems":1,"type":"array","items":{"type":"string","enum":["port.created","port.deleted","port.expiring","port.expired","port.rotated","port.suspended","port.unsuspended","customer.created","customer.updated","customer.suspended","customer.unsuspended","customer.tier_upgraded","customer.quota_warning","customer.quota_exceeded","traffic.threshold_50","traffic.threshold_80","traffic.threshold_100","balance.low","balance.topup","purchase.completed"]},"description":"Events to subscribe to","example":["port.created","port.expiring","customer.quota_warning"]},"secret":{"type":"string","description":"Secret for HMAC signature verification","example":"whsec_abc123xyz"},"headers":{"type":"object","description":"Custom headers to send with webhook","example":{"X-Custom-Header":"value"}}},"required":["name","url","events"]},"UpdateWebhookDto":{"type":"object","properties":{"name":{"type":"string","description":"Webhook name","example":"My App Webhook"},"url":{"type":"string","format":"uri","description":"Webhook URL","example":"https://myapp.com/webhooks/proxies"},"events":{"type":"array","items":{"type":"string","enum":["port.created","port.deleted","port.expiring","port.expired","port.rotated","port.suspended","port.unsuspended","customer.created","customer.updated","customer.suspended","customer.unsuspended","customer.tier_upgraded","customer.quota_warning","customer.quota_exceeded","traffic.threshold_50","traffic.threshold_80","traffic.threshold_100","balance.low","balance.topup","purchase.completed"]},"description":"Events to subscribe to"},"secret":{"type":"string","description":"Secret for HMAC signature verification"},"isActive":{"type":"boolean","description":"Whether webhook is active"},"headers":{"type":"object","description":"Custom headers to send with webhook"}}},"TestWebhookDto":{"type":"object","properties":{"eventType":{"enum":["port.created","port.deleted","port.expiring","port.expired","port.rotated","port.suspended","port.unsuspended","customer.created","customer.updated","customer.suspended","customer.unsuspended","customer.tier_upgraded","customer.quota_warning","customer.quota_exceeded","traffic.threshold_50","traffic.threshold_80","traffic.threshold_100","balance.low","balance.topup","purchase.completed"],"type":"string","description":"Event type to test","default":"port.created"}}},"CreatePortForCustomerDto":{"type":"object","properties":{"customerId":{"type":"string","description":"Customer ID to create port for"},"countryId":{"type":"string","description":"Country ID for the port"},"cityId":{"type":"string","description":"City ID (optional)"},"carrierId":{"type":"string","description":"Carrier ID (optional)"},"exclusive":{"type":"boolean","description":"Exclusive device access","default":false},"isPrivate":{"type":"boolean","description":"Private device (1 port per modem)","default":false},"days":{"type":"number","minimum":1,"description":"Port duration in days","default":30}},"required":["customerId","countryId"]},"CheckQuotaDto":{"type":"object","properties":{"customerId":{"type":"string","description":"Customer ID to check quota for","example":"507f1f77bcf86cd799439011"}},"required":["customerId"]},"CalculatePortPriceDto":{"type":"object","properties":{"customerId":{"type":"string","description":"Customer ID","example":"507f1f77bcf86cd799439011"},"countryId":{"type":"string","description":"Country ID for country-specific pricing","example":"507f1f77bcf86cd799439012"},"days":{"type":"number","minimum":1,"description":"Number of days for the port","example":30},"isPrivate":{"type":"boolean","description":"Whether this is a private (dedicated) port","default":false}},"required":["customerId","days"]},"ExtendPortDto":{"type":"object","properties":{"days":{"type":"number","minimum":1,"description":"Number of days to extend","example":30}},"required":["days"]},"SuspendPortDto":{"type":"object","properties":{"reason":{"type":"string","description":"Reason for suspension","example":"Payment overdue"}}},"CreatePoolAccessKeyDto":{"type":"object","properties":{"label":{"type":"string","minLength":1,"maxLength":256,"pattern":"LABEL_REGEX","description":"Human label, 1-256 chars","example":"customer:alice@example.com"},"trafficCapGB":{"type":"number","nullable":true,"minimum":1,"maximum":100000,"description":"GB cap for this key. Null = unbounded within reseller pool.","example":10},"expiresAt":{"type":"string","nullable":true,"description":"ISO datetime, must be in the future, at most 5 years out.","example":"2026-08-30T00:00:00Z"}},"required":["label"]},"UpdatePoolAccessKeyDto":{"type":"object","properties":{"label":{"type":"string","minLength":1,"maxLength":256,"pattern":"LABEL_REGEX","example":"customer:alice@example.com"},"enabled":{"type":"boolean","example":true},"trafficCapGB":{"type":"number","nullable":true,"minimum":1,"maximum":100000,"example":25},"expiresAt":{"type":"string","nullable":true,"example":"2026-08-30T00:00:00Z"}}},"TopUpPoolAccessKeyDto":{"type":"object","properties":{"addTrafficGB":{"type":"number","minimum":1,"maximum":100000,"description":"GB to add to the cap atomically.","example":10},"extendDays":{"type":"number","minimum":1,"maximum":1825,"description":"Days to extend expiresAt forward.","example":30}}},"RegisterDeviceDto":{"type":"object","properties":{"deviceId":{"type":"string","description":"Unique device identifier","example":"psx_abc123xyz"},"apiKey":{"type":"string","description":"Developer API key (for SDK integrations)","example":"dev_xxx"},"model":{"type":"string","description":"Device model","example":"Pixel 7a"},"osVersion":{"type":"string","description":"OS version","example":"Android 14"},"appVersion":{"type":"string","description":"App version","example":"1.0.2"},"sdkVersion":{"type":"string","description":"SDK version","example":"1.0.2"},"country":{"type":"string","description":"Country code","example":"US"},"carrier":{"type":"string","description":"Carrier name","example":"Verizon"},"userId":{"type":"string","description":"Developer user ID (for linking earnings)","example":"user-123"}},"required":["deviceId"]},"UpdateDeviceStatusDto":{"type":"object","properties":{"status":{"type":"string","enum":["online","offline"]},"currentIp":{"type":"string","description":"Current IP address"},"relayServer":{"type":"string","description":"Relay server hostname"},"country":{"type":"string","description":"Country code (e.g., TH, US)"},"carrier":{"type":"string","description":"Carrier name"}},"required":["status"]},"TrafficEntryDto":{"type":"object","properties":{"customerId":{"type":"string","description":"Customer ID (system for gateway)","example":"system"},"deviceId":{"type":"string","description":"Peer device ID","example":"psx_32caa58ac42acd03"},"timestamp":{"format":"date-time","type":"string","description":"Traffic timestamp (ISO 8601)","example":"2026-01-28T06:37:00.000Z"},"method":{"type":"string","description":"HTTP method","example":"PROXY"},"targetHost":{"type":"string","description":"Target hostname","example":"multiple"},"targetPort":{"type":"number","minimum":0,"description":"Target port","example":0},"bytesIn":{"type":"number","minimum":0,"description":"Bytes received","example":100000},"bytesOut":{"type":"number","minimum":0,"description":"Bytes sent","example":200000},"responseStatus":{"type":"number","minimum":0,"description":"HTTP response status","example":200},"durationMs":{"type":"number","minimum":0,"description":"Request duration in milliseconds","example":0},"proxyType":{"type":"string","description":"Proxy type","enum":["http","https"],"example":"http"},"sessionId":{"type":"string","description":"Session identifier"},"userAgent":{"type":"string","description":"User agent string"},"error":{"type":"string","description":"Error message if any"}},"required":["customerId","deviceId","timestamp","method","targetHost","targetPort","bytesIn","bytesOut","responseStatus","durationMs","proxyType"]},"RecordTrafficBatchDto":{"type":"object","properties":{"entries":{"description":"Array of traffic entries","type":"array","items":{"$ref":"#/components/schemas/TrafficEntryDto"}}},"required":["entries"]},"WithdrawAgentDto":{"type":"object","properties":{"walletAddress":{"type":"string","minLength":32,"maxLength":44,"pattern":"/^[1-9A-HJ-NP-Za-km-z]+$/","description":"Solana wallet address for USDC payout (32-44 base58 characters)","example":"6eUdVwsPArTxwVqEARYGCh4S2qwW2zCs7jSEDRpxydnv"}},"required":["walletAddress"]},"GatewayAuthDto":{"type":"object","properties":{"accountId":{"type":"string","maxLength":256,"description":"Account ID (proxy username prefix, e.g., psx_abc123)","example":"psx_abc123"},"password":{"type":"string","maxLength":128,"description":"Account password","example":"mySecurePassword123"}},"required":["accountId","password"]},"GatewayAuthResponseDto":{"type":"object","properties":{"valid":{"type":"boolean","description":"Whether authentication was successful"},"userId":{"type":"string","description":"User ID if valid"},"email":{"type":"string","description":"User email if valid"},"balance":{"type":"number","description":"Remaining balance in cents"},"hasSubscription":{"type":"boolean","description":"Whether user has active subscription"},"rateLimit":{"type":"number","description":"Rate limit (requests per minute)"},"error":{"type":"string","description":"Error message if invalid"},"pakKeyId":{"type":"string","description":"Pool-access-key id (when pak_ auth used)"}},"required":["valid"]},"RegisterPeerDto":{"type":"object","properties":{"email":{"type":"string","format":"email","example":"user@example.com"},"password":{"type":"string","minLength":6,"example":"securePassword123"},"name":{"type":"string","example":"John Doe"},"referralCode":{"type":"string","example":"PEER_ABC123","description":"Referral code from another user"}},"required":["email","password"]},"LoginPeerDto":{"type":"object","properties":{"email":{"type":"string","format":"email","example":"user@example.com"},"password":{"type":"string","example":"securePassword123"}},"required":["email","password"]},"UpdatePasswordDto":{"type":"object","properties":{"currentPassword":{"type":"string","example":"currentPassword123"},"newPassword":{"type":"string","example":"newPassword456"}}},"LinkDeviceDto":{"type":"object","properties":{"deviceId":{"type":"string","pattern":"/^psx_[a-f0-9]+$/","example":"psx_32caa58ac42acd03","description":"Device ID from the peer app (starts with psx_)"}},"required":["deviceId"]},"UpdateWalletsDto":{"type":"object","properties":{"usdt":{"type":"string","pattern":"/^T[a-zA-Z0-9]{33}$/","example":"TQn8vKxxxxxxxxxxxxxxxxxxxxxxxx","description":"USDT TRC-20 wallet address"},"btc":{"type":"string","example":"bc1qxxxxxxxxxxxxxxxxxxxxxxxx","description":"Bitcoin wallet address"},"sol":{"type":"string","example":"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx","description":"Solana wallet address"},"paypal":{"type":"string","example":"user@paypal.com","description":"PayPal email address"}}},"UpdateProfileDto":{"type":"object","properties":{"name":{"type":"string","example":"John Doe"}}},"RegisterDeveloperDto":{"type":"object","properties":{"email":{"type":"string","format":"email","example":"dev@acmegames.com"},"password":{"type":"string","minLength":6,"example":"securePassword123"},"companyName":{"type":"string","example":"Acme Games Inc"},"contactName":{"type":"string","example":"John Smith"},"website":{"type":"string","format":"uri","example":"https://acmegames.com"}},"required":["email","password","companyName"]},"LoginDeveloperDto":{"type":"object","properties":{"email":{"type":"string","format":"email","example":"dev@acmegames.com"},"password":{"type":"string","example":"securePassword123"}},"required":["email","password"]},"CreateAppDto":{"type":"object","properties":{"name":{"type":"string","example":"Puzzle Quest"},"packageName":{"type":"string","pattern":"/^[a-z][a-z0-9_]*(\\.[a-z][a-z0-9_]*)+$/i","example":"com.acme.puzzlequest"},"category":{"type":"string","example":"game","enum":["game","fitness","utility","social","entertainment","other"]},"platform":{"type":"string","enum":["android","ios","both"],"default":"android"},"description":{"type":"string","example":"A fun puzzle game with rewards"}},"required":["name"]},"UpdateAppDto":{"type":"object","properties":{"name":{"type":"string","example":"Puzzle Quest Pro"},"description":{"type":"string","example":"An updated description"}}},"RequestDeveloperPayoutDto":{"type":"object","properties":{"method":{"type":"string","enum":["usdt","paypal","bank"],"example":"usdt","description":"Payout method"}},"required":["method"]},"UpdatePayoutDetailsDto":{"type":"object","properties":{"usdt":{"type":"string","example":"TQn8vKxxxxxxxxxxxxxxxxxxxxxxxx"},"paypal":{"type":"string","example":"payments@acmegames.com"},"bankTransfer":{"type":"object","properties":{"accountName":{"type":"string"},"accountNumber":{"type":"string"},"bankName":{"type":"string"},"swift":{"type":"string"},"country":{"type":"string"}},"required":[]}}}}}}