/** * WC Licensed Product API Client for C# * * A C# client for interacting with the WC Licensed Product REST API. * * Requirements: * - .NET 6.0+ or .NET Framework 4.7.2+ * - System.Net.Http * - System.Text.Json (or Newtonsoft.Json) * * Usage: * var client = new WcLicensedProductClient("https://your-site.com"); * var result = await client.ValidateAsync("XXXX-XXXX-XXXX-XXXX", "example.com"); */ using System; using System.Net.Http; using System.Net.Http.Headers; using System.Text; using System.Text.Json; using System.Text.Json.Serialization; using System.Threading.Tasks; namespace WcLicensedProduct { /// /// License status response data /// public class LicenseStatus { [JsonPropertyName("valid")] public bool Valid { get; set; } [JsonPropertyName("status")] public string Status { get; set; } [JsonPropertyName("domain")] public string Domain { get; set; } [JsonPropertyName("expires_at")] public string ExpiresAt { get; set; } [JsonPropertyName("activations_count")] public int ActivationsCount { get; set; } [JsonPropertyName("max_activations")] public int MaxActivations { get; set; } } /// /// Validation response data /// public class ValidationResult { [JsonPropertyName("valid")] public bool Valid { get; set; } [JsonPropertyName("error")] public string Error { get; set; } [JsonPropertyName("message")] public string Message { get; set; } [JsonPropertyName("license")] public LicenseInfo License { get; set; } } /// /// License information in validation response /// public class LicenseInfo { [JsonPropertyName("status")] public string Status { get; set; } [JsonPropertyName("domain")] public string Domain { get; set; } [JsonPropertyName("expires_at")] public string ExpiresAt { get; set; } [JsonPropertyName("product_id")] public int ProductId { get; set; } } /// /// Activation response data /// public class ActivationResult { [JsonPropertyName("success")] public bool Success { get; set; } [JsonPropertyName("error")] public string Error { get; set; } [JsonPropertyName("message")] public string Message { get; set; } } /// /// Exception for API errors /// public class WcLicensedProductException : Exception { public string ErrorCode { get; } public int HttpCode { get; } public WcLicensedProductException(string message, string errorCode = null, int httpCode = 0) : base(message) { ErrorCode = errorCode; HttpCode = httpCode; } } /// /// Exception for rate limit errors /// public class RateLimitException : WcLicensedProductException { public int RetryAfter { get; } public RateLimitException(int retryAfter) : base($"Rate limit exceeded. Retry after {retryAfter} seconds.") { RetryAfter = retryAfter; } } /// /// Client for the WC Licensed Product REST API /// public class WcLicensedProductClient : IDisposable { private readonly HttpClient _httpClient; private readonly string _baseUrl; private readonly JsonSerializerOptions _jsonOptions; /// /// Initialize the client /// /// Your WordPress site URL (e.g., "https://example.com") /// Request timeout (default: 30 seconds) public WcLicensedProductClient(string siteUrl, TimeSpan? timeout = null) { _baseUrl = siteUrl.TrimEnd('/') + "/wp-json/wc-licensed-product/v1"; _httpClient = new HttpClient { Timeout = timeout ?? TimeSpan.FromSeconds(30) }; _httpClient.DefaultRequestHeaders.Accept.Add( new MediaTypeWithQualityHeaderValue("application/json")); _jsonOptions = new JsonSerializerOptions { PropertyNameCaseInsensitive = true }; } /// /// Validate a license key for a specific domain /// /// The license key to validate /// The domain to validate against /// Validation result public async Task ValidateAsync(string licenseKey, string domain) { var data = new { license_key = licenseKey, domain = domain }; return await RequestAsync("/validate", data); } /// /// Get the status of a license /// /// The license key to check /// License status public async Task StatusAsync(string licenseKey) { var data = new { license_key = licenseKey }; return await RequestAsync("/status", data); } /// /// Activate a license on a domain /// /// The license key to activate /// The domain to activate on /// Activation result public async Task ActivateAsync(string licenseKey, string domain) { var data = new { license_key = licenseKey, domain = domain }; return await RequestAsync("/activate", data); } /// /// Make an API request /// private async Task RequestAsync(string endpoint, object data) { var url = _baseUrl + endpoint; var json = JsonSerializer.Serialize(data); var content = new StringContent(json, Encoding.UTF8, "application/json"); HttpResponseMessage response; try { response = await _httpClient.PostAsync(url, content); } catch (TaskCanceledException) { throw new WcLicensedProductException("Request timeout"); } catch (HttpRequestException ex) { throw new WcLicensedProductException($"Request failed: {ex.Message}"); } // Handle rate limiting if ((int)response.StatusCode == 429) { var retryAfter = 60; if (response.Headers.TryGetValues("Retry-After", out var values)) { int.TryParse(string.Join("", values), out retryAfter); } throw new RateLimitException(retryAfter); } var responseBody = await response.Content.ReadAsStringAsync(); T result; try { result = JsonSerializer.Deserialize(responseBody, _jsonOptions); } catch (JsonException) { throw new WcLicensedProductException("Invalid JSON response"); } // Check for API errors (for error responses) if (!response.IsSuccessStatusCode) { var errorResult = JsonSerializer.Deserialize(responseBody, _jsonOptions); if (errorResult?.Error != null) { throw new WcLicensedProductException( errorResult.Message ?? "Unknown error", errorResult.Error, (int)response.StatusCode ); } } return result; } public void Dispose() { _httpClient?.Dispose(); } } // ========================================================================= // Usage Examples // ========================================================================= public class Program { public static async Task Main(string[] args) { using var client = new WcLicensedProductClient("https://your-wordpress-site.com"); // Example 1: Validate a license Console.WriteLine("=== Validate License ==="); try { var result = await client.ValidateAsync("XXXX-XXXX-XXXX-XXXX", "myapp.example.com"); if (result.Valid) { Console.WriteLine("License is valid!"); Console.WriteLine($"Status: {result.License?.Status ?? "active"}"); Console.WriteLine($"Expires: {result.License?.ExpiresAt ?? "Never"}"); } else { Console.WriteLine($"License is not valid: {result.Message ?? "Unknown error"}"); } } catch (RateLimitException ex) { Console.WriteLine($"Rate limited. Retry after {ex.RetryAfter} seconds."); } catch (WcLicensedProductException ex) { Console.WriteLine($"Error: {ex.Message}"); } Console.WriteLine(); // Example 2: Check license status Console.WriteLine("=== Check License Status ==="); try { var status = await client.StatusAsync("XXXX-XXXX-XXXX-XXXX"); Console.WriteLine($"Valid: {(status.Valid ? "Yes" : "No")}"); Console.WriteLine($"Status: {status.Status ?? "unknown"}"); Console.WriteLine($"Domain: {status.Domain ?? "None"}"); Console.WriteLine($"Expires: {status.ExpiresAt ?? "Never"}"); Console.WriteLine($"Activations: {status.ActivationsCount}/{status.MaxActivations}"); } catch (RateLimitException ex) { Console.WriteLine($"Rate limited. Retry after {ex.RetryAfter} seconds."); } catch (WcLicensedProductException ex) { Console.WriteLine($"Error: {ex.Message}"); } Console.WriteLine(); // Example 3: Activate license on a domain Console.WriteLine("=== Activate License ==="); try { var result = await client.ActivateAsync("XXXX-XXXX-XXXX-XXXX", "newsite.example.com"); if (result.Success) { Console.WriteLine("License activated successfully!"); } else { Console.WriteLine($"Activation failed: {result.Message ?? "Unknown error"}"); } } catch (RateLimitException ex) { Console.WriteLine($"Rate limited. Retry after {ex.RetryAfter} seconds."); } catch (WcLicensedProductException ex) { Console.WriteLine($"Error ({ex.ErrorCode}): {ex.Message}"); } } } }