The API Manager PHP library adds license activation and automatic updates to a WordPress plugin or theme you sell with API Manager. You drop one file into your product and add a few lines of code. Your customers then get a license activation screen in their WordPress admin, a reminder until they activate, and updates through the normal WordPress update screens.
The library is free and open source on GitHub, which includes an example plugin and a Postman collection. This page covers version 2.12.2. For software that isn’t a WordPress plugin or theme, call the licensing API directly instead.
When you’d use this
- License a WordPress plugin or theme you sell from your WooCommerce store.
- Deliver updates to customers’ sites without hosting them on WordPress.org.
- Stop your plugin from running until the customer activates their key.
Requirements
- Your store runs the latest API Manager release, on HTTPS with a valid certificate.
- The product is a licensing product with a downloadable zip. See Set up licensing products in API Manager.
- Use the latest library release in new versions of your software. Each API Manager release shows a dismissible notice in your store’s admin naming the latest library version.
Add the library to your plugin or theme
1. Copy the file
Download wc-am-client.php from the GitHub repository and place it in your plugin’s root folder, or next to functions.php in a theme. The library doesn’t use Composer autoloading, so you load it yourself.
2. Load and start it first
Add this to your main plugin file, just below the plugin header, or at the top of your theme’s functions.php. Load it before the rest of your code, so activation and updates keep working even if something else in your product fails.
defined( 'ABSPATH' ) || exit;
if ( ! class_exists( 'WC_AM_Client_2_12_2' ) ) {
require_once plugin_dir_path( __FILE__ ) . 'wc-am-client.php';
}
if ( class_exists( 'WC_AM_Client_2_12_2' ) ) {
$wcam_lib = new WC_AM_Client_2_12_2(
__FILE__, // Main plugin file, or functions.php in a theme.
456, // Product ID.
null, // Parent product ID (leave null).
'1.2.3', // Your software's current version.
'plugin', // 'plugin' or 'theme'.
'https://example.com/', // Your store's root URL.
'Example Plugin', // Name used for the activation menu and notices.
'example-textdomain' // Your text domain.
);
}
The class name includes the library version, so several products using different library versions can run on the same site.
3. Set the constructor arguments
| Argument | What to pass |
|---|---|
$file | __FILE__ from your main plugin file or theme functions.php. |
$product_id | The Licensed product ID from the product’s Licensing tab. For a variable product, the ID of the variation the customer buys. Pass an empty string to have customers enter it themselves. |
$product_parent_id | Pass null. |
$software_version | The version of this release. Keep it in step with the Version on the product’s Licensing tab. |
$plugin_or_theme | 'plugin' or 'theme'. |
$api_url | Your store’s root URL, such as https://example.com/. |
$software_title | Your product’s name. It’s used for the activation menu ("Example Plugin activation") and notices, and isn’t sent to your store. |
$text_domain | Your product’s text domain, for translations. |
$custom_menu | Optional. An array to put the activation screen in your own menu (see below). |
$inactive_notice | Optional. false hides the "not activated" admin notice. Default true. |
Hard-code the product ID when you can: customers then only enter their license key, and there’s no risk of them entering the wrong product. If you sell license tiers as variations, each variation has its own product ID, so either build a download per tier or pass an empty string and let customers enter the product ID shown in My Account » License keys.
4. Release and test
Zip your product, upload it as the licensing product’s first downloadable file, and set the Version on its Licensing tab. Install the zip on a test site, activate it with a license key from a test order, and check that the activation appears on the order’s License activations box. Then raise the version, upload a new zip, and check that the test site offers the update.
Use your own menu
By default, the activation screen is added under Settings as "[software title] activation". To put it somewhere else, pass a custom menu array as the ninth argument:
$wcam_lib_custom_menu = array(
'menu_type' => 'add_submenu_page', // Or 'add_options_page' or 'add_menu_page'.
'parent_slug' => 'my-plugin.php',
'page_title' => 'My Plugin License Activation',
'menu_title' => 'License',
);
$wcam_lib = new WC_AM_Client_2_12_2( __FILE__, 456, null, '1.2.3', 'plugin', 'https://example.com/', 'Example Plugin', 'example-textdomain', $wcam_lib_custom_menu, false );
With a custom menu, you may want the tenth argument set to false to hide the "not activated" notice.
Require activation before your product runs
Wrap the code that loads your product in a status check, so it only runs once the key is activated:
if ( is_object( $wcam_lib ) && $wcam_lib->get_api_key_status() ) {
// Load your plugin or theme here.
}
Leave the argument out (or pass false) for this check: it reads the status saved at activation, without a request to your store. get_api_key_status( true ) asks your store for the live status, which is slower and meant for occasional checks after activation.
To activate a key from your own code, for example during onboarding, call $wcam_lib->activate_new_key( $api_key ).
What your customers see
- A reminder to activate. Until the key is activated, an admin notice says the license key hasn’t been activated, with a link to the activation screen. It doesn’t show on staging and local development sites.
- The activation screen. License key activation has a License key field (and a Product ID field when you didn’t hard-code it). After activation, Activation info shows Activations purchased, Total activations and Activations remaining. If activation fails, the error from your store appears there.
- License deactivation. A License key deactivation section frees the activation, so the customer can move the license to another site. Deactivating or deleting your plugin doesn’t free it by itself.
- Updates. When you release a new version, WordPress shows its usual update notice. View details shows the version, compatibility and changelog from the product’s Metadata and Documents. Once the key is activated, customers can turn auto-updates on or off for your plugin on the Plugins screen.

Each site where your product runs, including each site in a multisite network, has its own activation. When Ignore test activations is on in your store, activations from staging and local sites don’t use an activation; the library sends each site’s address so your store can tell.
Test requests with Postman
The repository’s resources folder has a Postman collection with every API request. Import it, set your store URL, license key, product ID and an instance ID, and send requests to see your store’s full responses. This is the quickest way to tell a store problem from a problem in your code. See the licensing API reference for each request.
Common issues
"Connection failed to the licensing server."
The customer’s site couldn’t get a valid response from your store. Check your store’s SSL certificate, then make sure no cache, CDN, firewall or security plugin blocks requests to ?wc-api=wc-am-api, and that PHP notices aren’t printed on your store. See Troubleshoot API Manager.
"Cannot activate license key. The license key has already been activated with the same unique instance ID sent with this request."
The site lost its saved activation but your store still has it. Delete that activation from My Account » License keys (or from the order’s License activations box), then activate again.
The activation screen asks for a product ID
You passed an empty product ID. Hard-code the Licensed product ID, or tell customers to copy the Product ID from My Account » License keys.
WordPress shows "Update package not available"
The key isn’t activated on that site, or the license has expired. Activate it again, then retry the update.
My code from an older library version stopped working
Version 2.10.0 added the $product_parent_id argument as the third argument, which shifts the rest. Add null as the third argument, and update the class name to the version you ship.
