2026-01-21 20:32:35 +01:00
{
"openapi" : "3.1.0" ,
"info" : {
"title" : "WooCommerce Licensed Product API" ,
2026-01-22 19:11:11 +01:00
"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." ,
2026-01-27 20:14:11 +01:00
"version" : "0.6.0" ,
2026-01-21 20:32:35 +01:00
"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" ,
2026-01-22 19:11:11 +01:00
"headers" : {
"X-License-Signature" : {
"$ref" : "#/components/headers/X-License-Signature"
} ,
"X-License-Timestamp" : {
"$ref" : "#/components/headers/X-License-Timestamp"
}
} ,
2026-01-21 20:32:35 +01:00
"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" ,
2026-01-22 19:11:11 +01:00
"headers" : {
"X-License-Signature" : {
"$ref" : "#/components/headers/X-License-Signature"
} ,
"X-License-Timestamp" : {
"$ref" : "#/components/headers/X-License-Timestamp"
}
} ,
2026-01-21 20:32:35 +01:00
"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" ,
2026-01-22 19:11:11 +01:00
"headers" : {
"X-License-Signature" : {
"$ref" : "#/components/headers/X-License-Signature"
} ,
"X-License-Timestamp" : {
"$ref" : "#/components/headers/X-License-Timestamp"
}
} ,
2026-01-21 20:32:35 +01:00
"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."
}
}
}
}
}
}
2026-01-27 20:14:11 +01:00
} ,
"/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"
}
}
}
2026-01-21 20:32:35 +01:00
}
} ,
"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"
}
}
} ,
"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"
}
}
2026-01-27 20:14:11 +01:00
} ,
"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"
}
}
}
}
2026-01-21 20:32:35 +01:00
}
} ,
"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
}
}
}
}
2026-01-22 19:11:11 +01:00
} ,
"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
}
2026-01-21 20:32:35 +01:00
}
} ,
"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"
2026-01-27 20:14:11 +01:00
} ,
{
"name" : "Plugin Updates" ,
"description" : "Check for plugin updates via WordPress-compatible API"
2026-01-21 20:32:35 +01:00
}
]
}