---
title: "API Manager licensing API reference"
url: "https://kestrelwp.com/docs/api-manager-licensing-api/"
description: "How your software activates, checks and deactivates API Manager license keys, with request and response details."
published: "2026-10-06T20:27:12+00:00"
modified: "2026-10-06T20:27:12+00:00"
---

API Manager answers licensing requests from your software at your store’s root URL. Your software sends a license key, a product ID and an instance ID, and the store replies in JSON with whether the key is activated, how many activations are left and, for updates, a download link. The [PHP library](/docs/woocommerce-api-manager-php-library-for-plugins-and-themes-documentation/) does all of this for WordPress plugins and themes; use this reference to build your own client for anything else.

## When you’d use this

- License desktop or mobile apps, SaaS accounts or software that isn’t a WordPress plugin or theme.
- Check a license from a server, for example before granting access to a service.
- Debug what the PHP library sends, using Postman.

## How requests work

Send a GET or POST request to your store’s root URL with `wc-api=wc-am-api` and a `wc_am_action`:

```
https://example.com/?wc-api=wc-am-api&wc_am_action=activate&api_key=KEY&product_id=456&instance=abc123XYZ&object=customer.example.net&version=1.2.3
```

Mind the trailing slash on your store URL, so there’s no double slash before the query string. Use HTTPS. Every response is JSON and includes `success` and `api_call_execution_time`; errors also include `code`, `error` and a `data` object with `error_code` and `error`.

### Request keys

| Key | What it is |
|---|---|
| `wc_am_action` | The action: `activate`, `deactivate`, `status`, `information`, `update`, `product_list` or `verify_api_key_is_active`. |
| `api_key` | The customer’s user license key or product license key. |
| `product_id` | The **Licensed product ID** from the product’s **Licensing** tab. For variable products, the variation’s ID. Hard-code it in your software where you can. |
| `instance` | A unique ID your software creates for this installation (see below). |
| `object` | Where the key is activated, such as the site’s host name or a device name, without `http://` or `https://`. Recorded with the activation and used by **Ignore test activations**. |
| `version` | The installed version of your software. |
| `plugin_name` | For WordPress plugins, the plugin folder and main file, such as `my-plugin/my-plugin.php`. For themes, the theme folder name. Other software can send any value in the same format. |
| `slug` | For WordPress plugins and themes, the folder name, such as `my-plugin`. Optional on `update`, but recommended. |

Older key names are still accepted: `license_key` for `api_key`, `software_version` for `version`, `platform` for `object`, and `request` for `wc_am_action`.

### Instance IDs

An instance ID identifies one installation. Generate a random, unique string the first time your software activates (the PHP library uses a 12-character password from WordPress), store it, and send it with every request for that installation. Activating again with a new instance ID uses another activation. When the customer deactivates, you can keep the instance ID to reuse if they activate again.

## Actions

### activate

Activates the key for this instance. Required: `api_key`, `product_id`, `instance`. Optional: `object`, `version` (both saved with the activation).

```
{
  "activated": true,
  "message": "4 out of 5 activations remaining",
  "success": true,
  "data": {
    "unlimited_activations": false,
    "total_activations_purchased": 5,
    "total_activations": 1,
    "activations_remaining": 4
  },
  "api_call_execution_time": "0.057487 seconds"
}
```

### deactivate

Frees the activation for this instance. Required: `api_key`, `product_id`, `instance`. Returns `deactivated` and the updated activation counts.

### status

Reports whether this instance is activated and how many activations remain. Required: `api_key`, `product_id`, `instance`. Optional: `version`, which updates the version recorded for the activation. `status_check` is `active` or `inactive`, and `data.activated` is `true` or `false`. API Manager checks the license is still valid (not expired, subscription active) before replying.

### information

Returns the software’s details from the product’s **Metadata** and **Documents** (name, version, author, homepage, requirements, last updated, changelog and other sections), in the shape WordPress’s plugin information screen uses. Required: `product_id`, `plugin_name`. To authenticate the request, also send `api_key`, `instance` and `version`.

### update

Returns the latest version and, for an authenticated request from an activated installation, a download link in `data.package.package`. Required: `product_id`, `plugin_name`. To authenticate, also send `api_key`, `instance` and `version`; `slug` is optional. Without an activation that matches `api_key`, `product_id` and `instance`, the response has an empty `package`, and WordPress reports "Update package not available". The link expires after the store’s **URL expire time**.

```
{
  "success": true,
  "data": {
    "package": {
      "id": "my-plugin-456",
      "slug": "my-plugin",
      "plugin": "my-plugin/my-plugin.php",
      "new_version": "1.3.0",
      "url": "https://example.com/product/my-plugin/",
      "tested": "6.8",
      "upgrade_notice": "",
      "package": "https://example.com/?..."
    }
  },
  "api_call_execution_time": "0.049395 seconds"
}
```

### product\_list

Lists the products a key can activate, with product IDs, titles and order IDs (and subscription IDs for subscription licenses). Required: `api_key`, `instance`. The instance ID here only identifies the cached response; it doesn’t create an activation.

### verify\_api\_key\_is\_active

Returns `success: true` if the key exists and belongs to at least one active license. Required: `api_key`.

### Legacy actions

`plugininformation` and `pluginupdatecheck` are the `information` and `update` actions with serialized PHP responses, for the PHP library before version 2.0. Don’t use them in new software.

## Error messages

Errors return `"success": false` with the message in `error`:

| Message | Cause |
|---|---|
| "The following required query string data is missing: …" | A required key is empty or missing. |
| "No licensing resources exist. Login to My Account to verify there are activations remaining, and the license key and product ID are correct." | No active license matches the key and product ID. |
| "No licensing resources exist. Login to My Account to verify there are activations remaining, and the license key is correct." | From `product_list`: no active license matches the key. |
| "Cannot activate license key. No licensing resources available." | No activations are left. |
| "Cannot activate license key. The license key has already been activated with the same unique instance ID sent with this request." | That instance is already activated. |
| "The license key could not be deactivated." | No activation matches the key, product ID and instance. |
| "The license key is not active or does not exist." | From `verify_api_key_is_active`. |
| "A customer account does not exist for this license key." | The key doesn’t exist on this store: it was mistyped, or it was replaced. |
| "The access for this license key has been disabled, or a license key was sent that does not exist on this store." | The customer’s user license key is disabled on their user profile, so none of their keys work. |
| "The product ID … could not be found in this store." | From `information` and `update`: the product ID isn’t a licensing product. |
| "The source did not send a required IP address." / "The source is not trusted." | Trusted sources are set and the request didn’t match. |
| "Request value does not exist." | Unknown `wc_am_action`. |

In the full responses, links to **My Account** are included as HTML. [Troubleshoot API Manager](/docs/troubleshoot-api-manager/#activation-errors) explains how to fix each one for a customer.

## Staging and local activations

With **Ignore test activations** on (the default), an `activate` request whose `object` is a staging or local development address, such as `*.local`, `*.test` or a host’s staging domain, succeeds without being stored or counted. Send the site’s host name as `object` so your store can tell. Updates work as usual.

## Trusted sources

To accept requests only from known servers, list their IP addresses in `wp-config.php`:

```
define( 'WC_AM_TRUSTED_SOURCES', array( '192.0.2.10', '2001:db8::10' ) );
```

Every request must then include `ip_address` with the server’s IP. API Manager checks both that value and the IP the request came from against the list, and rejects the request unless both match. If your servers sit behind a load balancer or proxy, make sure the request’s IP reaches your store as one of the listed addresses.

## Caching and performance

API Manager caches license lookups and responses to keep API requests fast, and refreshes the cache when licenses, orders or products change.

- `define( 'WC_AM_ENABLE_CACHE', false );` in `wp-config.php` turns that caching off, which helps while you develop and test against live data.
- API Manager sends no-cache headers on your home page, where requests arrive. `define( 'WC_AM_DISABLE_HOMEPAGE_CACHE', false );` stops that, for stores that want their home page cached; then make sure your page cache or CDN never caches requests with `wc-api=wc-am-api` in the query string.

Firewalls and security services that block query strings or automated requests can break the API, so allow requests to `?wc-api=wc-am-api`.

## Test with Postman

The PHP library repository on [GitHub](https://github.com/kestrelcommerce/wc-api-manager-php-library) includes a Postman collection with every action. Import it, set your store URL and the keys for a test license, and send requests to see the full responses. Turn on **Server error log** under **API Manager » Configuration » Debug** to see the store’s side.

## Common issues

### Requests return the home page instead of JSON

A cache, CDN or firewall answered the request, or rewrote its query string. Exclude `wc-api=wc-am-api` from caching and security rules.

### Responses include PHP notices

`WP_DEBUG_DISPLAY` is printing notices into the response, which breaks the JSON. Turn debug display off on your store.

### Activation works but update checks fail

`update` and `information` need `plugin_name`, and an authenticated `update` also needs `version` and the same `instance` used to activate. Check the request in the **Server error log**.

## Keep learning

- [API Manager PHP library for plugins and themes](/docs/woocommerce-api-manager-php-library-for-plugins-and-themes-documentation/)
- [Troubleshoot API Manager](/docs/troubleshoot-api-manager/)
- [API Manager settings](/docs/api-manager-settings/)
- [Set up licensing products in API Manager](/docs/set-up-api-manager-licensing-products/)
