{ "openapi": "3.1.0", "info": { "title": "WooCommerce Licensed Product API", "description": "REST API for validating and managing software licenses bound to domains. This API allows external applications to validate license keys, check license status, and activate licenses on specific domains.\n\n## Response Signing (Optional)\n\nWhen the server is configured with `WC_LICENSE_SERVER_SECRET`, all API responses include cryptographic signatures for tamper protection:\n\n- `X-License-Signature`: HMAC-SHA256 signature of the response\n- `X-License-Timestamp`: Unix timestamp when the response was generated\n\nSignature verification prevents man-in-the-middle attacks and ensures response integrity. Use the `magdev/wc-licensed-product-client` library's `SecureLicenseClient` class to automatically verify signatures.", "version": "0.4.0", "contact": { "name": "Marco Graetsch", "url": "https://src.bundespruefstelle.ch/magdev", "email": "magdev3.0@gmail.com" }, "license": { "name": "GPL-2.0-or-later", "url": "https://www.gnu.org/licenses/gpl-2.0.html" } }, "servers": [ { "url": "{baseUrl}/wp-json/wc-licensed-product/v1", "description": "WordPress REST API endpoint", "variables": { "baseUrl": { "default": "https://example.com", "description": "The base URL of your WordPress installation" } } } ], "paths": { "/validate": { "post": { "operationId": "validateLicense", "summary": "Validate a license key for a domain", "description": "Validates whether a license key is valid for a specific domain. Checks license status, expiration, and domain binding. This is the primary endpoint for software to verify license validity.", "tags": ["License Validation"], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ValidateRequest" }, "example": { "license_key": "ABCD-1234-EFGH-5678", "domain": "example.com" } }, "application/x-www-form-urlencoded": { "schema": { "$ref": "#/components/schemas/ValidateRequest" } } } }, "responses": { "200": { "description": "License is valid for the specified domain", "headers": { "X-License-Signature": { "$ref": "#/components/headers/X-License-Signature" }, "X-License-Timestamp": { "$ref": "#/components/headers/X-License-Timestamp" } }, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ValidateSuccessResponse" }, "example": { "valid": true, "license": { "product_id": 123, "expires_at": "2027-01-21", "version_id": 5 } } } } }, "403": { "description": "License validation failed", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ValidateErrorResponse" }, "examples": { "license_not_found": { "summary": "License key not found", "value": { "valid": false, "error": "license_not_found", "message": "License key not found." } }, "license_revoked": { "summary": "License has been revoked", "value": { "valid": false, "error": "license_revoked", "message": "This license has been revoked." } }, "license_expired": { "summary": "License has expired", "value": { "valid": false, "error": "license_expired", "message": "This license has expired." } }, "license_inactive": { "summary": "License is inactive", "value": { "valid": false, "error": "license_inactive", "message": "This license is inactive." } }, "domain_mismatch": { "summary": "License not valid for this domain", "value": { "valid": false, "error": "domain_mismatch", "message": "This license is not valid for this domain." } } } } } }, "429": { "$ref": "#/components/responses/RateLimitExceeded" } } } }, "/status": { "post": { "operationId": "checkStatus", "summary": "Get license status information", "description": "Retrieves detailed status information for a license key, including validity, domain binding, expiration date, and activation counts.", "tags": ["License Status"], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/StatusRequest" }, "example": { "license_key": "ABCD-1234-EFGH-5678" } }, "application/x-www-form-urlencoded": { "schema": { "$ref": "#/components/schemas/StatusRequest" } } } }, "responses": { "200": { "description": "License status retrieved successfully", "headers": { "X-License-Signature": { "$ref": "#/components/headers/X-License-Signature" }, "X-License-Timestamp": { "$ref": "#/components/headers/X-License-Timestamp" } }, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/StatusResponse" }, "example": { "valid": true, "status": "active", "domain": "example.com", "expires_at": "2027-01-21", "activations_count": 1, "max_activations": 3 } } } }, "404": { "description": "License key not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" }, "example": { "valid": false, "error": "license_not_found", "message": "License key not found." } } } }, "429": { "$ref": "#/components/responses/RateLimitExceeded" } } } }, "/activate": { "post": { "operationId": "activateLicense", "summary": "Activate a license on a domain", "description": "Activates a license key on a specific domain. If the license is already activated on the same domain, returns success. If activating on a new domain, the old domain binding is replaced (single-domain licenses).", "tags": ["License Activation"], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ActivateRequest" }, "example": { "license_key": "ABCD-1234-EFGH-5678", "domain": "newdomain.com" } }, "application/x-www-form-urlencoded": { "schema": { "$ref": "#/components/schemas/ActivateRequest" } } } }, "responses": { "200": { "description": "License activated successfully or already activated", "headers": { "X-License-Signature": { "$ref": "#/components/headers/X-License-Signature" }, "X-License-Timestamp": { "$ref": "#/components/headers/X-License-Timestamp" } }, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ActivateSuccessResponse" }, "examples": { "activated": { "summary": "License activated on new domain", "value": { "success": true, "message": "License activated successfully." } }, "already_activated": { "summary": "License already activated on this domain", "value": { "success": true, "message": "License is already activated for this domain." } } } } } }, "403": { "description": "Activation failed due to license restrictions", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" }, "examples": { "license_invalid": { "summary": "License is not valid", "value": { "success": false, "error": "license_invalid", "message": "This license is not valid." } }, "max_activations_reached": { "summary": "Maximum activations reached", "value": { "success": false, "error": "max_activations_reached", "message": "Maximum number of activations reached." } } } } } }, "404": { "description": "License key not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" }, "example": { "success": false, "error": "license_not_found", "message": "License key not found." } } } }, "429": { "$ref": "#/components/responses/RateLimitExceeded" }, "500": { "description": "Server error during activation", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" }, "example": { "success": false, "error": "activation_failed", "message": "Failed to activate license." } } } } } } }, "/update-check": { "post": { "operationId": "checkForUpdates", "summary": "Check for plugin updates", "description": "Checks if a newer version of the licensed product is available. Returns WordPress-compatible update information that can be used to integrate with WordPress's native plugin update system.", "tags": ["Plugin Updates"], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdateCheckRequest" }, "example": { "license_key": "ABCD-1234-EFGH-5678", "domain": "example.com", "plugin_slug": "my-licensed-plugin", "current_version": "1.0.0" } }, "application/x-www-form-urlencoded": { "schema": { "$ref": "#/components/schemas/UpdateCheckRequest" } } } }, "responses": { "200": { "description": "Update check completed successfully", "headers": { "X-License-Signature": { "$ref": "#/components/headers/X-License-Signature" }, "X-License-Timestamp": { "$ref": "#/components/headers/X-License-Timestamp" } }, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdateCheckResponse" }, "examples": { "update_available": { "summary": "Update is available", "value": { "success": true, "update_available": true, "version": "1.2.0", "slug": "my-licensed-plugin", "plugin": "my-licensed-plugin/my-licensed-plugin.php", "download_url": "https://example.com/license-download/123-456-abc123", "package": "https://example.com/license-download/123-456-abc123", "last_updated": "2026-01-27", "tested": "6.7", "requires": "6.0", "requires_php": "8.3", "changelog": "## 1.2.0\n- New feature added\n- Bug fixes", "package_hash": "sha256:abc123def456...", "name": "My Licensed Plugin", "homepage": "https://example.com/product/my-plugin" } }, "no_update": { "summary": "No update available", "value": { "success": true, "update_available": false, "version": "1.0.0" } } } } } }, "403": { "description": "License validation failed", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" }, "examples": { "license_invalid": { "summary": "License is not valid", "value": { "success": false, "update_available": false, "error": "license_invalid", "message": "License validation failed." } }, "domain_mismatch": { "summary": "Domain mismatch", "value": { "success": false, "update_available": false, "error": "domain_mismatch", "message": "This license is not valid for this domain." } } } } } }, "404": { "description": "License or product not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" }, "examples": { "license_not_found": { "summary": "License not found", "value": { "success": false, "update_available": false, "error": "license_not_found", "message": "License not found." } }, "product_not_found": { "summary": "Product not found", "value": { "success": false, "update_available": false, "error": "product_not_found", "message": "Licensed product not found." } } } } } }, "429": { "$ref": "#/components/responses/RateLimitExceeded" } } } } }, "components": { "schemas": { "ValidateRequest": { "type": "object", "required": ["license_key", "domain"], "properties": { "license_key": { "type": "string", "description": "The license key to validate (format: XXXX-XXXX-XXXX-XXXX)", "maxLength": 64, "example": "ABCD-1234-EFGH-5678" }, "domain": { "type": "string", "description": "The domain to validate the license against", "maxLength": 255, "example": "example.com" } } }, "ValidateSuccessResponse": { "type": "object", "properties": { "valid": { "type": "boolean", "const": true, "description": "Indicates the license is valid" }, "license": { "type": "object", "properties": { "product_id": { "type": "integer", "description": "WooCommerce product ID associated with the license" }, "expires_at": { "type": ["string", "null"], "format": "date", "description": "Expiration date (null for lifetime licenses)" }, "version_id": { "type": ["integer", "null"], "description": "Product version ID if license is bound to a version" } } } } }, "ValidateErrorResponse": { "type": "object", "properties": { "valid": { "type": "boolean", "const": false, "description": "Indicates validation failed" }, "error": { "type": "string", "enum": ["license_not_found", "license_revoked", "license_expired", "license_inactive", "domain_mismatch"], "description": "Error code for programmatic handling" }, "message": { "type": "string", "description": "Human-readable error message" } } }, "StatusRequest": { "type": "object", "required": ["license_key"], "properties": { "license_key": { "type": "string", "description": "The license key to check", "example": "ABCD-1234-EFGH-5678" } } }, "StatusResponse": { "type": "object", "properties": { "valid": { "type": "boolean", "description": "Whether the license is currently valid" }, "status": { "type": "string", "enum": ["active", "inactive", "expired", "revoked"], "description": "Current license status" }, "domain": { "type": "string", "description": "Domain the license is bound to" }, "expires_at": { "type": ["string", "null"], "format": "date", "description": "Expiration date (null for lifetime licenses)" }, "activations_count": { "type": "integer", "description": "Current number of activations" }, "max_activations": { "type": "integer", "description": "Maximum allowed activations" } } }, "ActivateRequest": { "type": "object", "required": ["license_key", "domain"], "properties": { "license_key": { "type": "string", "description": "The license key to activate", "example": "ABCD-1234-EFGH-5678" }, "domain": { "type": "string", "description": "The domain to activate the license on", "example": "newdomain.com" } } }, "ActivateSuccessResponse": { "type": "object", "properties": { "success": { "type": "boolean", "const": true, "description": "Indicates activation was successful" }, "message": { "type": "string", "description": "Human-readable success message" } } }, "UpdateCheckRequest": { "type": "object", "required": ["license_key", "domain"], "properties": { "license_key": { "type": "string", "description": "The license key to validate (format: XXXX-XXXX-XXXX-XXXX)", "maxLength": 64, "example": "ABCD-1234-EFGH-5678" }, "domain": { "type": "string", "description": "The domain the plugin is installed on", "maxLength": 255, "example": "example.com" }, "plugin_slug": { "type": "string", "description": "The plugin slug (optional, for identification)", "example": "my-licensed-plugin" }, "current_version": { "type": "string", "description": "Currently installed version for comparison", "example": "1.0.0" } } }, "UpdateCheckResponse": { "type": "object", "properties": { "success": { "type": "boolean", "description": "Whether the request was successful" }, "update_available": { "type": "boolean", "description": "Whether an update is available" }, "version": { "type": "string", "description": "Latest available version" }, "slug": { "type": "string", "description": "Plugin slug for WordPress" }, "plugin": { "type": "string", "description": "Plugin basename (slug/slug.php)" }, "download_url": { "type": "string", "format": "uri", "description": "Secure download URL for the update package" }, "package": { "type": "string", "format": "uri", "description": "Alias for download_url (WordPress compatibility)" }, "last_updated": { "type": "string", "format": "date", "description": "Date of the latest release" }, "tested": { "type": "string", "description": "Highest WordPress version tested with" }, "requires": { "type": "string", "description": "Minimum required WordPress version" }, "requires_php": { "type": "string", "description": "Minimum required PHP version" }, "changelog": { "type": "string", "description": "Release notes/changelog for the update" }, "package_hash": { "type": "string", "description": "SHA256 hash of the package for integrity verification", "example": "sha256:abc123..." }, "name": { "type": "string", "description": "Product name" }, "homepage": { "type": "string", "format": "uri", "description": "Product homepage URL" }, "icons": { "type": "object", "description": "Plugin icons for WordPress admin", "properties": { "1x": { "type": "string", "format": "uri" }, "2x": { "type": "string", "format": "uri" } } }, "sections": { "type": "object", "description": "Content sections for plugin info modal", "properties": { "description": { "type": "string" }, "changelog": { "type": "string" } } } } }, "ErrorResponse": { "type": "object", "properties": { "success": { "type": "boolean", "const": false, "description": "Indicates the operation failed" }, "valid": { "type": "boolean", "const": false, "description": "Indicates validation failed (for validation endpoints)" }, "error": { "type": "string", "description": "Error code for programmatic handling" }, "message": { "type": "string", "description": "Human-readable error message" } } }, "RateLimitResponse": { "type": "object", "properties": { "success": { "type": "boolean", "const": false }, "error": { "type": "string", "const": "rate_limit_exceeded" }, "message": { "type": "string", "example": "Too many requests. Please try again later." }, "retry_after": { "type": "integer", "description": "Seconds until rate limit resets" } } } }, "responses": { "RateLimitExceeded": { "description": "Rate limit exceeded (30 requests per minute per IP)", "headers": { "Retry-After": { "schema": { "type": "integer" }, "description": "Seconds until the rate limit resets" } }, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RateLimitResponse" }, "example": { "success": false, "error": "rate_limit_exceeded", "message": "Too many requests. Please try again later.", "retry_after": 45 } } } } }, "headers": { "X-License-Signature": { "description": "HMAC-SHA256 signature of the response body for tamper protection. Only present when server is configured with WC_LICENSE_SERVER_SECRET. Signature format: hex-encoded HMAC-SHA256 of (timestamp + ':' + canonical_json_body) using a per-license derived key.", "schema": { "type": "string", "pattern": "^[a-f0-9]{64}$", "example": "a1b2c3d4e5f6789012345678901234567890abcdef1234567890abcdef123456" }, "required": false }, "X-License-Timestamp": { "description": "Unix timestamp when the response was generated. Used together with X-License-Signature to prevent replay attacks. Only present when server is configured with WC_LICENSE_SERVER_SECRET.", "schema": { "type": "string", "pattern": "^[0-9]+$", "example": "1737550000" }, "required": false } } }, "tags": [ { "name": "License Validation", "description": "Validate license keys against domains" }, { "name": "License Status", "description": "Check license status and details" }, { "name": "License Activation", "description": "Activate licenses on domains" }, { "name": "Plugin Updates", "description": "Check for plugin updates" } ] }