Documentation
Everything you need to integrate and run Licensify.
Overview
Licensify lets you validate license keys by domain. A client (e.g. WordPress plugin, SaaS app) sends license_key and domain to POST /api/validate-license and receives success or error. The server checks key validity, expiry, and domain binding. First successful validation can bind the license to that domain.
Base URL: https://licensify.mkbuilds.live. All API responses are JSON. Send Accept: application/json for validation error responses in JSON.
API Reference
Validate license
Check whether a license key is valid for a given domain.
- Endpoint:
POST https://licensify.mkbuilds.live/api/validate-license - Rate limit: 10 requests per minute per IP
- Auth: None (public endpoint for client validation)
Request
Content-Type: application/x-www-form-urlencoded or application/json.
| Parameter | Type | Required | Description |
|---|---|---|---|
| license_key | string | Yes | The license key |
| domain | string | Yes | Domain to validate (e.g. example.com or www.example.com). Normalized server-side (lowercase, no protocol/path, www stripped) |
Responses
Success
Status: 200 OK
{
"status": "success",
"message": "License validation successful"
}
Validation failed (invalid/expired/wrong domain)
Status: 403 Forbidden
{
"status": "error",
"message": "License validation failed"
}
Invalid input (e.g. missing domain)
Status: 422 Unprocessable Entity
{
"message": "Domain is required.",
"errors": {
"domain": ["Domain is required."]
}
}
Behavior
- If the license has no domain set, the first successful validation binds the license to the given domain.
- Subsequent validations must use the same (normalized) domain.
- Domains are normalized: same effective domain (e.g.
example.comvswww.example.com) is treated as one. - Expired or inactive licenses return the same generic error for security (no enumeration).
Examples
cURL:
curl -X POST https://licensify.mkbuilds.live/api/validate-license \
-H "Accept: application/json" \
-d "license_key=XXXX-XXXX-XXXX-XXXX" \
-d "domain=example.com"
PHP (WordPress / plain PHP):
$response = wp_remote_post($url . '/api/validate-license', [
'timeout' => 15,
'body' => [
'license_key' => $license_key,
'domain' => parse_url(home_url(), PHP_URL_HOST),
],
]);
$code = wp_remote_retrieve_response_code($response);
$body = json_decode(wp_remote_retrieve_body($response), true);
$valid = ($code === 200 && isset($body['status']) && $body['status'] === 'success');
A drop-in PHP helper with caching is available in the repo: docs/wordpress-license-client.php. Use it in your plugin to validate licenses and cache the result (e.g. 24h).
Other API routes
- GET /api/user — Returns the authenticated user (Sanctum). Requires
Authorization: Bearer <token>.
What works today
| Feature | Status |
|---|---|
| License validation API | Working |
| Domain binding (first-use locks to domain) | Working |
| Expiry checking | Working |
| Active/inactive toggle | Working |
| Filament admin panel (create/edit licenses) | Working |
| API rate limiting (60 req/min general; 10/min on validate) | Present |
| CORS enabled for API | Present |
Implemented
The following items from the production checklist are already in place:
- ✓ Input validation —
license_keyanddomainvalidated via Form Request - ✓ Domain normalization — Strip protocol, path, port; lowercase;
wwwstripped so www.example.com = example.com - ✓ Stricter rate limiting — 10 requests per minute per IP on
/api/validate-license - ✓ Generic error messages — Single “License validation failed” for all failure cases; detailed reason logged server-side
- ✓ Auto-generate license keys — In Filament Create License, leave key empty to get format XXXX-XXXX-XXXX-XXXX
- ✓ WordPress client helper —
docs/wordpress-license-client.phpwith caching and clear usage - ✓ Activation audit log —
license_activationstable; every validation (success/failure) logged; viewable in Filament per license - ✓ API documentation — This page
- ✓ Automated tests — Feature tests for valid key, invalid key, expired, inactive, domain mismatch, domain normalization, validation errors
Remaining gaps
Consider adding these for production or commercial use:
- License deactivation / transfer — Customer moves site; license is bound to old domain. Add “Deactivate” or “Reset domain” in admin, or customer-facing deactivation with verification.
-
Product / version support — Single product only. Add
product_idorproduct_slugto licenses and optionalproductparam on validate for multi-product licensing. -
Updates endpoint — Add
GET /api/check-updates?license_key=...&domain=...¤t_version=...returning latest version and download URL if valid (for plugin update checks). - Customer self-service portal — Let customers view their licenses and deactivate for transfer (e.g. login with license_key + email or integrate with store).
Nice-to-have (later)
| Item | Description |
|---|---|
| Email notifications | Notify on license expiry, first activation, deactivation |
| License tiers | Different limits (e.g. sites count, features) |
| Webhook on validation | Notify external systems (CRM, analytics) |
| Soft delete licenses | Keep history instead of hard delete |
| HTTPS enforcement | Force SSL in production |
| Environment config | APP_DEBUG=false, proper APP_URL for production |
WordPress integration checklist
To use this server with a WordPress plugin (e.g. M-Pesa plugin):
- Add license settings in the plugin: license key input, “Activate” / “Deactivate” buttons.
- On activation: POST to
https://licensify.mkbuilds.live/api/validate-licensewithlicense_keyanddomain(fromsite_url()orparse_url(home_url(), PHP_URL_HOST)). - Cache result (transient, 12–24h) to avoid repeated API calls.
- Gate features: If validation fails, show “License required” and limit functionality.
- Optional: Periodic re-validation (e.g. weekly cron) or on plugin load.
Use the provided docs/wordpress-license-client.php helper: instantiate with your API URL and product slug, call validate($license_key, $domain), and optionally clearCache() on deactivation.
Recommended priority order
If you are implementing remaining items, this order is suggested:
- Input validation — Implemented
- Domain normalization — Implemented
- Stricter rate limiting on validate — Implemented (10/min)
- Generic error messages — Implemented
- Auto-generate license keys — Implemented
- WordPress client helper — Implemented
- Activation audit log — Implemented
- API documentation — Implemented
- License deactivation / transfer
- Automated tests — Implemented
Conclusion
Licensify is functional and suitable for internal or early use. Critical items (validation, domain normalization, security, client integration) are implemented. Remaining gaps (deactivation, multi-product, updates endpoint, customer portal) will make it more robust for commercial sale. With the current implementation you can create accounts, generate license keys, validate them via API, and view activation history in the dashboard.