Initialize composer project for WooCommerce Licensed Product Client

- Set up composer.json with package metadata and PSR-4 autoloading
- Add symfony/http-client ^7.0 as HTTP client dependency
- Create project structure (src/, tests/, tmp/)
- Add README.md with project overview
- Add CHANGELOG.md to track version history
- Add .gitignore for vendor and cache files
- Include OpenAPI specification in tmp/openapi.json

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-22 15:37:20 +01:00
commit 1fdedd16ad
8 changed files with 1293 additions and 0 deletions

15
.editorconfig Normal file
View File

@@ -0,0 +1,15 @@
# EditorConfig is awesome: https://EditorConfig.org
# top-most EditorConfig file
root = true
[*]
indent_style = space
indent_size = 4
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.md]
indent_size = 2

9
.gitignore vendored Normal file
View File

@@ -0,0 +1,9 @@
/vendor/
.phpunit.result.cache
.php-cs-fixer.cache
*.log
.DS_Store
.idea/
.vscode/
*.swp
*.swo

18
CHANGELOG.md Normal file
View File

@@ -0,0 +1,18 @@
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased]
## [0.0.1] - 2026-01-22
### Added
- Initial composer project setup
- Package configuration with PSR-4 autoloading
- Symfony HttpClient dependency (^7.0)
- Project documentation (README.md, CHANGELOG.md)
- OpenAPI specification reference in tmp/openapi.json

91
CLAUDE.md Normal file
View File

@@ -0,0 +1,91 @@
# License-Client for WooCommerce Licensed Product Plugin
**Author:** Marco Graetsch
**Author URL:** <https://src.bundespruefstelle.ch/magdev>
**Author Email:** <magdev3.0@gmail.com>
**Repository URL:** <https://src.bundespruefstelle.ch/magdev/wc-licensed-product-client>
**Issues URL:** <https://src.bundespruefstelle.ch/magdev/wc-licensed-product-client/issues>
**Package-Name:** `magdev/wc-licensed-product-client`
## Project Overview
This composer package implements a Client for the WooCommerce Licensed Product Plugin. It uses the REST API as described in `tmp/openapi.json` to activate, validate and check the status of licenses.
## Features
- Easy integration in licensed software packages
- Defines a PHP constant if a licensed is valid or not
- Obfuscate the security critical code parts using plain PHP tools as best as possible
### Key Fact: 100% AI-Generated
This project is proudly **"vibe-coded"** using Claude.AI - the entire codebase was created through AI assistance.
## Temporary Roadmap
**Note for AI Assistants:** Clean this section after the specific features are done or new releases are made. Effective changes are tracked in `CHANGELOG.md`. Do not add completed versions here - document them in the Session History section at the end of this file.
### Known Bugs
No known bugs at the moment
### Version 0.0.1
- Initialize composer project of type `library` with the known details
- Install dependencies
## Technical Stack
- **Language:** PHP 8.3.x
- **Coding-Style:** Symfony
- **HTTP-Client-Library:** symfony/http-client
- **Dependency Management:** Composer
- **OpenAPI Description:** `tmp/openapi.json`
---
**For AI Assistants:**
When starting a new session on this project:
1. Read this CLAUDE.md file first
2. Semantic versioning follows the `MAJOR.MINOR.BUGFIX` pattern
3. Check git log for recent changes
4. Verify you're on the `dev` branch before making changes
5. Run `composer install` if vendor/ is missing
6. Test changes before committing
7. Follow commit message format with Claude Code attribution
8. Update this session history section with learnings
9. Always update the `README.md` on related changes
10. Keep changes in a single `CHANGELOG.md`
11. Follow markdown linting rules (see below)
Always refer to this document when starting work on this project.
### Markdown Linting Rules
When editing CLAUDE.md or other markdown files, follow these rules to avoid linting errors:
1. **MD031 - Blank lines around fenced code blocks**: Always add a blank line before and after fenced code blocks, even when they follow list items. Example of correct format:
- **Item label**:
(blank line here)
\`\`\`php
code example
\`\`\`
(blank line here)
2. **MD056 - Table column count**: Table separators must have matching column counts and proper spacing. Use consistent dash lengths that match column header widths.
3. **MD009 - No trailing spaces**: Remove trailing whitespace from lines
4. **MD012 - No multiple consecutive blank lines**: Use only single blank lines between sections
5. **MD040 - Fenced code blocks should have a language specified**: Always add a language identifier to code blocks (e.g., `txt`, `bash`, `php`). For shortcode examples, use `txt`.
6. **MD032 - Lists should be surrounded by blank lines**: Add a blank line before AND after list blocks, including after bold labels like `**Attributes:**`.
7. **MD034 - Bare URLs**: Wrap URLs in angle brackets (e.g., `<https://example.com>`) or use markdown link syntax `[text](url)`.
8. **Author section formatting**: Use a heading (`### Name`) instead of bold (`**Name**`) for the author name to maintain consistent document structure.

49
README.md Normal file
View File

@@ -0,0 +1,49 @@
# WooCommerce Licensed Product Client
A PHP client library for the WooCommerce Licensed Product Plugin REST API. Activate, validate, and check the status of software licenses.
## Requirements
- PHP 8.3 or higher
- Composer
## Installation
```bash
composer require magdev/wc-licensed-product-client
```
## Features
- Easy integration in licensed software packages
- License validation against domains
- License activation on domains
- License status checking
- Built on Symfony HttpClient
## API Endpoints
This client interacts with the following WooCommerce Licensed Product API endpoints:
- **POST /validate** - Validate a license key for a specific domain
- **POST /status** - Get detailed license status information
- **POST /activate** - Activate a license on a domain
## Usage
Coming soon in future versions.
## License
GPL-2.0-or-later
## Author
Marco Graetsch
- Website: <https://src.bundespruefstelle.ch/magdev>
- Email: <magdev3.0@gmail.com>
## Contributing
Issues and pull requests are welcome at <https://src.bundespruefstelle.ch/magdev/wc-licensed-product-client/issues>

36
composer.json Normal file
View File

@@ -0,0 +1,36 @@
{
"name": "magdev/wc-licensed-product-client",
"description": "Client library for WooCommerce Licensed Product Plugin - Activate, validate and check the status of licenses via REST API",
"type": "library",
"license": "GPL-2.0-or-later",
"authors": [
{
"name": "Marco Graetsch",
"email": "magdev3.0@gmail.com",
"homepage": "https://src.bundespruefstelle.ch/magdev"
}
],
"homepage": "https://src.bundespruefstelle.ch/magdev/wc-licensed-product-client",
"support": {
"issues": "https://src.bundespruefstelle.ch/magdev/wc-licensed-product-client/issues",
"source": "https://src.bundespruefstelle.ch/magdev/wc-licensed-product-client"
},
"require": {
"php": "^8.3",
"symfony/http-client": "^7.0"
},
"autoload": {
"psr-4": {
"Magdev\\WcLicensedProductClient\\": "src/"
}
},
"autoload-dev": {
"psr-4": {
"Magdev\\WcLicensedProductClient\\Tests\\": "tests/"
}
},
"config": {
"sort-packages": true
},
"minimum-stability": "stable"
}

537
composer.lock generated Normal file
View File

@@ -0,0 +1,537 @@
{
"_readme": [
"This file locks the dependencies of your project to a known state",
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "dabb6ce648c8b638dc4b20b8999dea1d",
"packages": [
{
"name": "psr/container",
"version": "2.0.2",
"source": {
"type": "git",
"url": "https://github.com/php-fig/container.git",
"reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/container/zipball/c71ecc56dfe541dbd90c5360474fbc405f8d5963",
"reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963",
"shasum": ""
},
"require": {
"php": ">=7.4.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.0.x-dev"
}
},
"autoload": {
"psr-4": {
"Psr\\Container\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "PHP-FIG",
"homepage": "https://www.php-fig.org/"
}
],
"description": "Common Container Interface (PHP FIG PSR-11)",
"homepage": "https://github.com/php-fig/container",
"keywords": [
"PSR-11",
"container",
"container-interface",
"container-interop",
"psr"
],
"support": {
"issues": "https://github.com/php-fig/container/issues",
"source": "https://github.com/php-fig/container/tree/2.0.2"
},
"time": "2021-11-05T16:47:00+00:00"
},
{
"name": "psr/log",
"version": "3.0.2",
"source": {
"type": "git",
"url": "https://github.com/php-fig/log.git",
"reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/log/zipball/f16e1d5863e37f8d8c2a01719f5b34baa2b714d3",
"reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3",
"shasum": ""
},
"require": {
"php": ">=8.0.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.x-dev"
}
},
"autoload": {
"psr-4": {
"Psr\\Log\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "PHP-FIG",
"homepage": "https://www.php-fig.org/"
}
],
"description": "Common interface for logging libraries",
"homepage": "https://github.com/php-fig/log",
"keywords": [
"log",
"psr",
"psr-3"
],
"support": {
"source": "https://github.com/php-fig/log/tree/3.0.2"
},
"time": "2024-09-11T13:17:53+00:00"
},
{
"name": "symfony/deprecation-contracts",
"version": "v3.6.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/deprecation-contracts.git",
"reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/63afe740e99a13ba87ec199bb07bbdee937a5b62",
"reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62",
"shasum": ""
},
"require": {
"php": ">=8.1"
},
"type": "library",
"extra": {
"thanks": {
"url": "https://github.com/symfony/contracts",
"name": "symfony/contracts"
},
"branch-alias": {
"dev-main": "3.6-dev"
}
},
"autoload": {
"files": [
"function.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "A generic function and convention to trigger deprecation notices",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/deprecation-contracts/tree/v3.6.0"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2024-09-25T14:21:43+00:00"
},
{
"name": "symfony/http-client",
"version": "v7.4.3",
"source": {
"type": "git",
"url": "https://github.com/symfony/http-client.git",
"reference": "d01dfac1e0dc99f18da48b18101c23ce57929616"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/http-client/zipball/d01dfac1e0dc99f18da48b18101c23ce57929616",
"reference": "d01dfac1e0dc99f18da48b18101c23ce57929616",
"shasum": ""
},
"require": {
"php": ">=8.2",
"psr/log": "^1|^2|^3",
"symfony/deprecation-contracts": "^2.5|^3",
"symfony/http-client-contracts": "~3.4.4|^3.5.2",
"symfony/polyfill-php83": "^1.29",
"symfony/service-contracts": "^2.5|^3"
},
"conflict": {
"amphp/amp": "<2.5",
"amphp/socket": "<1.1",
"php-http/discovery": "<1.15",
"symfony/http-foundation": "<6.4"
},
"provide": {
"php-http/async-client-implementation": "*",
"php-http/client-implementation": "*",
"psr/http-client-implementation": "1.0",
"symfony/http-client-implementation": "3.0"
},
"require-dev": {
"amphp/http-client": "^4.2.1|^5.0",
"amphp/http-tunnel": "^1.0|^2.0",
"guzzlehttp/promises": "^1.4|^2.0",
"nyholm/psr7": "^1.0",
"php-http/httplug": "^1.0|^2.0",
"psr/http-client": "^1.0",
"symfony/amphp-http-client-meta": "^1.0|^2.0",
"symfony/cache": "^6.4|^7.0|^8.0",
"symfony/dependency-injection": "^6.4|^7.0|^8.0",
"symfony/http-kernel": "^6.4|^7.0|^8.0",
"symfony/messenger": "^6.4|^7.0|^8.0",
"symfony/process": "^6.4|^7.0|^8.0",
"symfony/rate-limiter": "^6.4|^7.0|^8.0",
"symfony/stopwatch": "^6.4|^7.0|^8.0"
},
"type": "library",
"autoload": {
"psr-4": {
"Symfony\\Component\\HttpClient\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Provides powerful methods to fetch HTTP resources synchronously or asynchronously",
"homepage": "https://symfony.com",
"keywords": [
"http"
],
"support": {
"source": "https://github.com/symfony/http-client/tree/v7.4.3"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://github.com/nicolas-grekas",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2025-12-23T14:50:43+00:00"
},
{
"name": "symfony/http-client-contracts",
"version": "v3.6.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/http-client-contracts.git",
"reference": "75d7043853a42837e68111812f4d964b01e5101c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/http-client-contracts/zipball/75d7043853a42837e68111812f4d964b01e5101c",
"reference": "75d7043853a42837e68111812f4d964b01e5101c",
"shasum": ""
},
"require": {
"php": ">=8.1"
},
"type": "library",
"extra": {
"thanks": {
"url": "https://github.com/symfony/contracts",
"name": "symfony/contracts"
},
"branch-alias": {
"dev-main": "3.6-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Contracts\\HttpClient\\": ""
},
"exclude-from-classmap": [
"/Test/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Generic abstractions related to HTTP clients",
"homepage": "https://symfony.com",
"keywords": [
"abstractions",
"contracts",
"decoupling",
"interfaces",
"interoperability",
"standards"
],
"support": {
"source": "https://github.com/symfony/http-client-contracts/tree/v3.6.0"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2025-04-29T11:18:49+00:00"
},
{
"name": "symfony/polyfill-php83",
"version": "v1.33.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php83.git",
"reference": "17f6f9a6b1735c0f163024d959f700cfbc5155e5"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-php83/zipball/17f6f9a6b1735c0f163024d959f700cfbc5155e5",
"reference": "17f6f9a6b1735c0f163024d959f700cfbc5155e5",
"shasum": ""
},
"require": {
"php": ">=7.2"
},
"type": "library",
"extra": {
"thanks": {
"url": "https://github.com/symfony/polyfill",
"name": "symfony/polyfill"
}
},
"autoload": {
"files": [
"bootstrap.php"
],
"psr-4": {
"Symfony\\Polyfill\\Php83\\": ""
},
"classmap": [
"Resources/stubs"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony polyfill backporting some PHP 8.3+ features to lower PHP versions",
"homepage": "https://symfony.com",
"keywords": [
"compatibility",
"polyfill",
"portable",
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-php83/tree/v1.33.0"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://github.com/nicolas-grekas",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2025-07-08T02:45:35+00:00"
},
{
"name": "symfony/service-contracts",
"version": "v3.6.1",
"source": {
"type": "git",
"url": "https://github.com/symfony/service-contracts.git",
"reference": "45112560a3ba2d715666a509a0bc9521d10b6c43"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/service-contracts/zipball/45112560a3ba2d715666a509a0bc9521d10b6c43",
"reference": "45112560a3ba2d715666a509a0bc9521d10b6c43",
"shasum": ""
},
"require": {
"php": ">=8.1",
"psr/container": "^1.1|^2.0",
"symfony/deprecation-contracts": "^2.5|^3"
},
"conflict": {
"ext-psr": "<1.1|>=2"
},
"type": "library",
"extra": {
"thanks": {
"url": "https://github.com/symfony/contracts",
"name": "symfony/contracts"
},
"branch-alias": {
"dev-main": "3.6-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Contracts\\Service\\": ""
},
"exclude-from-classmap": [
"/Test/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Generic abstractions related to writing services",
"homepage": "https://symfony.com",
"keywords": [
"abstractions",
"contracts",
"decoupling",
"interfaces",
"interoperability",
"standards"
],
"support": {
"source": "https://github.com/symfony/service-contracts/tree/v3.6.1"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://github.com/nicolas-grekas",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2025-07-15T11:30:57+00:00"
}
],
"packages-dev": [],
"aliases": [],
"minimum-stability": "stable",
"stability-flags": {},
"prefer-stable": false,
"prefer-lowest": false,
"platform": {
"php": "^8.3"
},
"platform-dev": {},
"plugin-api-version": "2.6.0"
}

538
tmp/openapi.json Normal file
View File

@@ -0,0 +1,538 @@
{
"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.",
"version": "0.0.7",
"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",
"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",
"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",
"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."
}
}
}
}
}
}
}
},
"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"
}
}
}
},
"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
}
}
}
}
}
},
"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"
}
]
}