You've already forked wc-licensed-product
- Add UpdateController REST API endpoint for serving update info to licensed plugins - Add PluginUpdateChecker singleton for client-side update checking - Hook into WordPress native plugin update system (pre_set_site_transient_update_plugins, plugins_api) - Add Auto-Updates settings subtab with enable/disable and check frequency options - Add authentication headers for secure download requests - Support configurable cache TTL for update checks (default 12 hours) - Document /update-check endpoint in OpenAPI specification - Update German translations Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
853 lines
28 KiB
JSON
853 lines
28 KiB
JSON
{
|
|
"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.6.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"
|
|
}
|
|
}
|
|
},
|
|
"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"
|
|
}
|
|
}
|
|
},
|
|
"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"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"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 via WordPress-compatible API"
|
|
}
|
|
]
|
|
}
|