Why validate license keys at all?
If you sell software, you need to validate license keys for the same reason a cinema checks tickets at the door: without the check, the product works exactly as well for someone who paid as for someone who did not. The moment you decide to validate license keys, the next question is where that check happens — and for a WordPress product, a REST API is almost always the answer.
The pattern below is the one most licensing systems settle on. Your plugin sends the key and the site it is running on; the server answers valid or invalid and says why. Everything else — activation limits, expiry, refunds, grace periods — is a variation on that one exchange.
How to Validate License Keys via REST API in WordPress (2026)
License key validation is one of the most critical components of any software distribution system. Whether you sell WordPress plugins, themes, or SaaS tools, you need a reliable way for customer installations to verify that a license key is legitimate, active, and authorized for the requesting domain. Without proper validation, you have no control over unauthorized use of your products.
The good news: if you are running DMSI DDLS (Digital Licensing & Distribution System) on your WordPress site, you already have a fully functional REST API for wordpress REST API license validation built in. DDLS exposes public endpoints that your plugins and themes can call remotely to validate, activate, and deactivate license keys — no complex setup required.
In this tutorial, we will walk through exactly how to implement license key validation using the DMSI DDLS REST API. You will get working PHP code examples that you can drop directly into your WordPress plugin or theme, along with best practices for caching, error handling, and security.
How REST API License Validation Works
Before diving into code, let’s understand the flow of a REST API license management system. The architecture is straightforward:
- Customer Site — The WordPress installation where your plugin or theme is activated. This is where the end user enters their license key.
- API Call — The customer site sends an HTTP request to your server, passing the license key and the requesting site URL as parameters.
- Your Server — Your WordPress site running DMSI DDLS receives the request, looks up the license key in its database, checks its status (active, expired, suspended, cancelled, or revoked), verifies domain limits, and prepares a response.
- Response — Your server returns a JSON response indicating whether the license is valid, along with metadata such as expiration date, activation count, and license tier.
This entire exchange happens over HTTPS in milliseconds. The key architectural decision DMSI DDLS makes is that validation, activation, and deactivation endpoints are public — they do not require authentication. This is intentional: the customer’s site needs to check license validity without storing your admin credentials. The license key itself serves as the authentication token for these operations.
For administrative operations like creating, updating, or deleting licenses, DDLS requires proper authentication via WordPress cookies, application passwords, or DDLS API keys. But for the three operations your distributed plugin needs — validate, activate, deactivate — the public endpoints are all you need.
Setting Up the API Endpoint
One of the advantages of DMSI DDLS is that the REST API endpoints are created automatically when you install and activate the plugin. There is no manual configuration needed to expose the API. The endpoints are registered under the dmsilm/v1 namespace, making them available at:
https://your-site.com/wp-json/dmsilm/v1/The three public endpoints you will use for license key validation PHP implementations are:
/wp-json/dmsilm/v1/licenses/validate— Check if a license key is valid and active/wp-json/dmsilm/v1/licenses/activate— Activate a license key for a specific domain/wp-json/dmsilm/v1/licenses/deactivate— Deactivate a license key from a specific domain
These public endpoints do not require any form of authentication — no API keys, no WordPress cookies, no application passwords. The license key parameter itself identifies and authorizes the request. This design means your distributed plugin only needs to know two things: the license key entered by the user and the URL of your DDLS-powered site.
DDLS also exposes authenticated endpoints for full CRUD (Create, Read, Update, Delete) operations on licenses. These are used for admin dashboards, external integrations, and automated provisioning. Authentication for these endpoints can be handled via WordPress cookies, application passwords, or DDLS API keys. DDLS also supports rate limiting to protect your server from abuse, and SSL requirements are configurable per your security policy. For the full details, see the API documentation.
License Validation — PHP Example
Let’s start with the most common operation: validating a license key. This is the function your plugin or theme will call to check whether the user’s license is legitimate and active. The following code is a complete, production-ready implementation of validate license key API logic:
/**
* Validate a license key against the DMSI DDLS API.
*
* @param string $license_key The license key to validate.
* @param string $api_url The base URL of the WordPress site running DMSI DDLS.
* @return array|false License data array on success, false on failure.
*/
function dmsi_validate_license( $license_key, $api_url ) {
$endpoint = trailingslashit( $api_url ) . 'wp-json/dmsilm/v1/licenses/validate';
$response = wp_remote_get( $endpoint, array(
'timeout' => 15,
'body' => array(
'license_key' => $license_key,
'site_url' => home_url(),
),
) );
if ( is_wp_error( $response ) ) {
return false;
}
$body = json_decode( wp_remote_retrieve_body( $response ), true );
if ( isset( $body['valid'] ) && $body['valid'] === true ) {
return $body;
}
return false;
}Here is what this function does step by step:
- Builds the endpoint URL — It takes the base URL of your DDLS site (e.g.,
https://your-store.com) and appends the validation endpoint path. Thetrailingslashit()function ensures proper URL formatting regardless of whether the user includes a trailing slash. - Sends the request — It uses
wp_remote_get()to send an HTTP GET request with two parameters: the license key and the requesting site’s URL. The 15-second timeout provides enough time for the remote server to respond while preventing your site from hanging indefinitely. - Handles errors — If the HTTP request fails (network error, DNS failure, timeout),
wp_remote_get()returns aWP_Errorobject. The function catches this and returnsfalse. - Parses the response — The JSON response body is decoded into a PHP associative array. If the
validfield istrue, the function returns the full response data (which includes license metadata like expiration date and activation count). Otherwise, it returnsfalse.
You can call this function from your plugin’s settings page, update checker, or feature-gating logic:
$license_data = dmsi_validate_license( $stored_key, 'https://your-store.com' );
if ( $license_data ) {
// License is valid — enable premium features
update_option( 'my_plugin_license_status', 'valid' );
update_option( 'my_plugin_license_expiry', $license_data['expires'] ?? '' );
} else {
// License is invalid or check failed — disable premium features
update_option( 'my_plugin_license_status', 'invalid' );
}License Activation — PHP Example
Validation checks whether a license is legitimate. Activation registers a specific site against that license, consuming one of the available activation slots. This is how you enforce per-site licensing. Here is the activation implementation:
/**
* Activate a license key via the DMSI DDLS API.
*
* @param string $license_key The license key to activate.
* @param string $api_url The base URL of the WordPress site running DMSI DDLS.
* @return array|false Activation response data on success, false on failure.
*/
function dmsi_activate_license( $license_key, $api_url ) {
$endpoint = trailingslashit( $api_url ) . 'wp-json/dmsilm/v1/licenses/activate';
$response = wp_remote_post( $endpoint, array(
'timeout' => 15,
'body' => array(
'license_key' => $license_key,
'site_url' => home_url(),
'site_name' => get_bloginfo( 'name' ),
),
) );
if ( is_wp_error( $response ) ) {
return false;
}
$body = json_decode( wp_remote_retrieve_body( $response ), true );
return $body;
}Note the differences from the validation function:
- Uses
wp_remote_post()— Activation is a state-changing operation, so it uses POST instead of GET. This follows REST conventions and ensures the request is not cached by intermediaries. - Sends
site_name— In addition to the license key and site URL, the activation request includes the site name. This helps you identify activations in the DDLS admin dashboard. - Returns the full response — Unlike validation, the activation function returns the entire response body regardless of success or failure. This allows your calling code to inspect error messages (e.g., “activation limit reached”) and display them to the user.
A typical activation flow in your plugin’s settings page would look like this:
// When the user clicks "Activate License"
$result = dmsi_activate_license( sanitize_text_field( $_POST['license_key'] ), 'https://your-store.com' );
if ( $result && isset( $result['activated'] ) && $result['activated'] === true ) {
update_option( 'my_plugin_license_key', sanitize_text_field( $_POST['license_key'] ) );
update_option( 'my_plugin_license_status', 'active' );
add_settings_error( 'my_plugin', 'license_activated', 'License activated successfully.', 'updated' );
} else {
$message = isset( $result['message'] ) ? $result['message'] : 'Activation failed. Please check your license key.';
add_settings_error( 'my_plugin', 'license_error', esc_html( $message ), 'error' );
}License Deactivation — PHP Example
Deactivation releases a site from a license key, freeing up an activation slot. Users need this when migrating to a new domain or decommissioning a site. The implementation follows the same pattern as activation:
/**
* Deactivate a license key via the DMSI DDLS API.
*
* @param string $license_key The license key to deactivate.
* @param string $api_url The base URL of the WordPress site running DMSI DDLS.
* @return array|false Deactivation response data on success, false on failure.
*/
function dmsi_deactivate_license( $license_key, $api_url ) {
$endpoint = trailingslashit( $api_url ) . 'wp-json/dmsilm/v1/licenses/deactivate';
$response = wp_remote_post( $endpoint, array(
'timeout' => 15,
'body' => array(
'license_key' => $license_key,
'site_url' => home_url(),
),
) );
if ( is_wp_error( $response ) ) {
return false;
}
$body = json_decode( wp_remote_retrieve_body( $response ), true );
return $body;
}Like activation, deactivation uses wp_remote_post() since it modifies server state. The request sends the license key and the site URL to identify which activation record to remove. You would typically call this function when a user clicks a “Deactivate License” button in your plugin settings, or automatically during plugin uninstallation via a register_uninstall_hook() callback.
// When the user clicks "Deactivate License"
$stored_key = get_option( 'my_plugin_license_key' );
if ( $stored_key ) {
$result = dmsi_deactivate_license( $stored_key, 'https://your-store.com' );
if ( $result && isset( $result['deactivated'] ) && $result['deactivated'] === true ) {
delete_option( 'my_plugin_license_key' );
update_option( 'my_plugin_license_status', 'inactive' );
add_settings_error( 'my_plugin', 'license_deactivated', 'License deactivated.', 'updated' );
} else {
$message = isset( $result['message'] ) ? $result['message'] : 'Deactivation failed.';
add_settings_error( 'my_plugin', 'license_error', esc_html( $message ), 'error' );
}
}Best Practices for License Validation
Having working code is only half the battle. To build a robust wordpress license check remote system, follow these best practices:
Cache Validation Results with Transients
Do not call the validation endpoint on every page load. Use WordPress transients to cache the result and reduce API calls. A reasonable cache duration is 12 to 24 hours for active licenses:
function dmsi_check_license_with_cache( $license_key, $api_url ) {
$cache_key = 'dmsi_license_' . md5( $license_key );
$cached = get_transient( $cache_key );
if ( $cached !== false ) {
return $cached;
}
$result = dmsi_validate_license( $license_key, $api_url );
if ( $result ) {
set_transient( $cache_key, $result, 12 * HOUR_IN_SECONDS );
} else {
// Cache failures briefly to avoid hammering the API
set_transient( $cache_key, array( 'valid' => false ), 1 * HOUR_IN_SECONDS );
}
return $result;
}Handle Errors Gracefully
Network failures happen. Your plugin should not break when the license server is temporarily unavailable. If a previously valid license cannot be re-validated due to a network error, continue operating in a degraded mode rather than immediately locking the user out. A common strategy is to allow a grace period of 3 to 7 days after the last successful validation before disabling features.
Always Use HTTPS
License keys are sensitive credentials. Always ensure your DDLS site uses SSL/TLS, and always use https:// in your API URL. DMSI DDLS supports configurable SSL requirements — in production, enable the SSL enforcement setting to reject any non-HTTPS API requests.
Never Hardcode License Keys
Store license keys in the WordPress database using update_option() and retrieve them with get_option(). Never hardcode keys in your plugin source code. If you need additional security, consider encrypting the stored key using WordPress salts.
Log Validation Attempts
Maintain a log of validation attempts for debugging. This is invaluable when customers report activation issues. You can use a simple custom log or integrate with an existing logging plugin:
if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
error_log( sprintf(
'[DMSI License] Validation for key %s from %s: %s',
substr( $license_key, 0, 8 ) . '...',
home_url(),
$result ? 'VALID' : 'INVALID'
) );
}Implement Retry with Backoff
If a validation request fails, do not immediately retry in a tight loop. Implement exponential backoff — wait 1 minute, then 5 minutes, then 30 minutes before retrying. This protects both your server and the customer’s site from unnecessary load.
Testing Your License Validation
Before shipping your plugin with license validation, test the integration thoroughly. Here is how:
Step 1: Create a Test License
In your WordPress admin running DMSI DDLS, navigate to DDLS > Licenses > Add New. Create a test license with known parameters — set the status to active, give it a reasonable expiration date, and set an activation limit of 2 or 3 sites.
Step 2: Test with curl
Before writing any PHP code, verify the API endpoints are working correctly using curl from your terminal:
# Test validation
curl -G "https://your-store.com/wp-json/dmsilm/v1/licenses/validate" \
--data-urlencode "license_key=YOUR-TEST-KEY" \
--data-urlencode "site_url=https://test-site.com"
# Test activation
curl -X POST "https://your-store.com/wp-json/dmsilm/v1/licenses/activate" \
-d "license_key=YOUR-TEST-KEY" \
-d "site_url=https://test-site.com" \
-d "site_name=Test Site"
# Test deactivation
curl -X POST "https://your-store.com/wp-json/dmsilm/v1/licenses/deactivate" \
-d "license_key=YOUR-TEST-KEY" \
-d "site_url=https://test-site.com"Step 3: Test Edge Cases
Make sure you test these scenarios:
- Invalid license key — The API should return a clear error, and your plugin should handle it gracefully.
- Expired license — Set a test license expiration to a past date and verify your plugin responds correctly.
- Activation limit reached — Activate the test license on enough sites to hit the limit, then try activating on one more.
- Suspended or revoked license — Change the test license status to suspended, cancelled, or revoked and verify the validation response. DDLS supports these statuses: active, expired, suspended, cancelled, and revoked.
- Network failure — Test with an unreachable URL to ensure your timeout and error handling work.
- Malformed response — Test that your code handles unexpected JSON structures without fatal errors.
Step 4: Verify in DDLS Dashboard
After running your tests, check the DDLS admin dashboard to confirm that activations and deactivations were recorded correctly. The license detail screen should show the correct number of active sites and their URLs.
Frequently Asked Questions
Do validation endpoints require authentication?
No. The validation, activation, and deactivation endpoints in DMSI DDLS are public — they do not require API keys, WordPress cookies, or application passwords. The license key itself serves as the identifier. This design is intentional: your distributed plugins need to make these calls from customer sites where you have no admin credentials. Administrative endpoints (creating, updating, deleting licenses) do require authentication via WordPress cookies, application passwords, or DDLS API keys.
How often should I validate licenses?
For most plugins, validating once every 12 to 24 hours is sufficient. Use WordPress transients to cache the result and avoid excessive API calls. Validate on plugin activation, on the settings page, and periodically via a scheduled cron event using wp_schedule_event(). Avoid validating on every page load — it adds unnecessary latency and load to both servers.
What happens if the API server is unreachable?
Your plugin should fail gracefully. If the last known validation was successful, continue operating normally for a defined grace period (3 to 7 days is reasonable). Store the timestamp of the last successful validation using update_option() and check it when the API is unreachable. Only disable premium features after the grace period expires and the API is still unreachable.
Can I validate licenses for non-WordPress applications?
Yes. The DDLS REST API is a standard HTTP JSON API. Any application that can make HTTP requests and parse JSON can use it — desktop applications, mobile apps, SaaS platforms, or custom PHP applications. Instead of wp_remote_get(), use your language’s HTTP client (e.g., file_get_contents(), cURL in PHP, requests in Python, fetch in JavaScript). The endpoint URLs and parameters remain the same. See the API documentation for language-specific examples.
Conclusion
Implementing wordpress REST API license validation with DMSI DDLS is straightforward. The plugin provides ready-to-use public endpoints for validation, activation, and deactivation — no complex setup, no manual endpoint registration, no authentication headaches for client-side calls. The PHP examples in this tutorial are production-ready and can be dropped directly into your plugin or theme.
To summarize the key implementation steps:
- Install DMSI DDLS on WordPress.org on your store site.
- Create licenses in the DDLS admin dashboard.
- Add the validation, activation, and deactivation functions to your plugin.
- Cache results with transients, handle errors gracefully, and enforce HTTPS.
- Test thoroughly with real and edge-case scenarios.
The combination of public validation endpoints and authenticated admin endpoints gives you full control over your licensing system while keeping the client-side implementation simple and secure.
Ready to get started? Check out the full feature list of DMSI DDLS, explore the API documentation for advanced use cases, or dive into the WordPress REST API reference for deeper understanding of the platform your license system runs on.

