""" WC Licensed Product API Client for Python A simple Python client for interacting with the WC Licensed Product REST API. Requirements: - Python 3.7+ - requests library (pip install requests) Usage: client = WcLicensedProductClient('https://your-site.com') result = client.validate('XXXX-XXXX-XXXX-XXXX', 'example.com') """ import requests from typing import Dict, Any, Optional from dataclasses import dataclass @dataclass class LicenseStatus: """License status response data.""" valid: bool status: str domain: Optional[str] expires_at: Optional[str] activations_count: int max_activations: int class WcLicensedProductError(Exception): """Base exception for API errors.""" def __init__(self, message: str, error_code: str = None, http_code: int = None): super().__init__(message) self.error_code = error_code self.http_code = http_code class RateLimitError(WcLicensedProductError): """Raised when rate limit is exceeded.""" def __init__(self, retry_after: int): super().__init__(f"Rate limit exceeded. Retry after {retry_after} seconds.") self.retry_after = retry_after class WcLicensedProductClient: """Client for the WC Licensed Product REST API.""" def __init__(self, site_url: str, timeout: int = 30): """ Initialize the client. Args: site_url: Your WordPress site URL (e.g., 'https://example.com') timeout: Request timeout in seconds """ self.base_url = site_url.rstrip('/') + '/wp-json/wc-licensed-product/v1' self.timeout = timeout self.session = requests.Session() self.session.headers.update({ 'Content-Type': 'application/json', 'Accept': 'application/json', }) def validate(self, license_key: str, domain: str) -> Dict[str, Any]: """ Validate a license key for a specific domain. Args: license_key: The license key to validate domain: The domain to validate against Returns: Dict with 'valid' boolean and additional license info Raises: WcLicensedProductError: On API error RateLimitError: When rate limited """ return self._request('/validate', { 'license_key': license_key, 'domain': domain, }) def status(self, license_key: str) -> LicenseStatus: """ Get the status of a license. Args: license_key: The license key to check Returns: LicenseStatus object with license details Raises: WcLicensedProductError: On API error RateLimitError: When rate limited """ data = self._request('/status', { 'license_key': license_key, }) return LicenseStatus( valid=data.get('valid', False), status=data.get('status', 'unknown'), domain=data.get('domain'), expires_at=data.get('expires_at'), activations_count=data.get('activations_count', 0), max_activations=data.get('max_activations', 1), ) def activate(self, license_key: str, domain: str) -> Dict[str, Any]: """ Activate a license on a domain. Args: license_key: The license key to activate domain: The domain to activate on Returns: Dict with 'success' boolean and message Raises: WcLicensedProductError: On API error RateLimitError: When rate limited """ return self._request('/activate', { 'license_key': license_key, 'domain': domain, }) def _request(self, endpoint: str, data: Dict[str, Any]) -> Dict[str, Any]: """ Make an API request. Args: endpoint: API endpoint path data: Request data Returns: Decoded response data Raises: WcLicensedProductError: On API error RateLimitError: When rate limited """ url = self.base_url + endpoint try: response = self.session.post(url, json=data, timeout=self.timeout) except requests.RequestException as e: raise WcLicensedProductError(f"Request failed: {e}") # Handle rate limiting if response.status_code == 429: retry_after = int(response.headers.get('Retry-After', 60)) raise RateLimitError(retry_after) try: result = response.json() except ValueError: raise WcLicensedProductError("Invalid JSON response") # Check for API errors if response.status_code >= 400 and 'error' in result: raise WcLicensedProductError( result.get('message', 'Unknown error'), error_code=result.get('error'), http_code=response.status_code, ) return result # ============================================================================= # Usage Examples # ============================================================================= if __name__ == '__main__': # Initialize the client client = WcLicensedProductClient('https://your-wordpress-site.com') # Example 1: Validate a license print("=== Validate License ===") try: result = client.validate('XXXX-XXXX-XXXX-XXXX', 'myapp.example.com') if result.get('valid'): print("License is valid!") print(f"Status: {result.get('license', {}).get('status', 'active')}") print(f"Expires: {result.get('license', {}).get('expires_at', 'Never')}") else: print(f"License is not valid: {result.get('message', 'Unknown error')}") except RateLimitError as e: print(f"Rate limited. Retry after {e.retry_after} seconds.") except WcLicensedProductError as e: print(f"Error: {e}") print() # Example 2: Check license status print("=== Check License Status ===") try: status = client.status('XXXX-XXXX-XXXX-XXXX') print(f"Valid: {'Yes' if status.valid else 'No'}") print(f"Status: {status.status}") print(f"Domain: {status.domain or 'None'}") print(f"Expires: {status.expires_at or 'Never'}") print(f"Activations: {status.activations_count}/{status.max_activations}") except RateLimitError as e: print(f"Rate limited. Retry after {e.retry_after} seconds.") except WcLicensedProductError as e: print(f"Error: {e}") print() # Example 3: Activate license on a domain print("=== Activate License ===") try: result = client.activate('XXXX-XXXX-XXXX-XXXX', 'newsite.example.com') if result.get('success'): print("License activated successfully!") else: print(f"Activation failed: {result.get('message', 'Unknown error')}") except RateLimitError as e: print(f"Rate limited. Retry after {e.retry_after} seconds.") except WcLicensedProductError as e: print(f"Error ({e.error_code}): {e}")