PHPackages                             code-heaven/license-sdk - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [API Development](/categories/api)
4. /
5. code-heaven/license-sdk

ActiveLibrary[API Development](/categories/api)

code-heaven/license-sdk
=======================

Vendor SDK for the Code Heaven Developer License API (validation, domain activation, updates, downloads).

v1.0.0(5d ago)00MITPHPPHP &gt;=8.0CI passing

Since Jun 4Pushed yesterdayCompare

[ Source](https://github.com/AskersCodes/code-heaven-license-sdk)[ Packagist](https://packagist.org/packages/code-heaven/license-sdk)[ RSS](/packages/code-heaven-license-sdk/feed)WikiDiscussions main Synced yesterday

READMEChangelogDependencies (1)Versions (2)Used By (0)

Code Heaven License SDK (PHP)
=============================

[](#code-heaven-license-sdk-php)

Vendor SDK for the **Code Heaven Developer License API**. Use it inside your plugin/theme/app to validate licenses, activate and free domain seats, check for updates, and fetch signed download URLs.

This is the **vendor server-to-server** flow. Authentication is a single vendor API key (`X-CH-Vendor-Key`), not the buyer OAuth flow.

- Base URL: `https://api.code-heaven.com/v1`
- PHP 8.0+
- No hard runtime dependencies (cURL or `file_get_contents`); pluggable HTTP so it works happily inside WordPress via `wp_remote_request`.

Install
-------

[](#install)

```
composer require code-heaven/license-sdk
```

Quick start: validate and gate
------------------------------

[](#quick-start-validate-and-gate)

```
use CodeHeaven\License\Client;
use CodeHeaven\License\LicenseException;
use CodeHeaven\License\TransportException;

$client = new Client('YOUR_VENDOR_KEY', [
    'cacheTtl'     => 12 * 3600,        // serve a fresh answer for 12h
    'offlineGrace' => 14 * 24 * 3600,   // keep working up to 14 days if the API is down
]);

try {
    $res = $client->validate('LICENSE-KEY', 'shop.example.com', 'booknetic-pro');
} catch (LicenseException $e) {
    // 403: invalid / expired / domain_not_activated  ($e->apiCode tells you which)
    bail("License problem: {$e->apiCode}");
} catch (TransportException $e) {
    // API unreachable AND no cached valid result within grace.
    bail('License server unreachable.');
}

if ($res['valid']) {
    enable_premium_features();
} else {
    // $res['status'] is one of: valid | invalid | expired | domain_not_activated | revoked
    disable_premium_features($res['status']);
}
```

`validate()` returns the decoded API body plus two SDK markers:

keymeaning`valid`bool`status``valid` | `invalid` | `expired` | `domain_not_activated` | `revoked``product`product slug (or `null`)`expiresAt`ISO 8601 string or `null``activations``[{domain, activatedAt}, ...]``seatLimit`int`_cached`present &amp; `true` when served from cache`_offline`present &amp; `true` when served from cache during an outageActivate a seat on first run
----------------------------

[](#activate-a-seat-on-first-run)

When `validate()` returns `domain_not_activated` (a `LicenseException` with `apiCode === 'domain_not_activated'`), claim a seat:

```
use CodeHeaven\License\SeatLimitException;

try {
    $client->activateDomain('LICENSE-KEY', 'shop.example.com');
} catch (SeatLimitException $e) {
    // 409 — buyer has used every seat; prompt them to deactivate another site.
}
```

Check for and apply an update
-----------------------------

[](#check-for-and-apply-an-update)

```
$update = $client->checkUpdate('LICENSE-KEY', 'booknetic-pro', '4.1.0', 'shop.example.com');

if ($update['hasUpdate']) {
    // latestVersion + changelog[{version,date,notes}]
    $dl = $client->download('LICENSE-KEY', 'booknetic-pro', 'shop.example.com', $update['latestVersion']);
    // $dl['url'] is a short-lived signed package URL; $dl['expiresAt'] tells you when it dies.
    download_and_install_zip($dl['url']);
}
```

Free the seat on uninstall
--------------------------

[](#free-the-seat-on-uninstall)

```
$client->deactivateDomain('LICENSE-KEY', 'shop.example.com');
```

Caching and offline grace
-------------------------

[](#caching-and-offline-grace)

`validate()` is cached so repeated calls in one request never hit the wire twice, and the result persists across requests when you supply a persistent cache:

- **`cacheTtl`** — how long a cached answer is considered *fresh*. Within this window `validate()` returns the cached body without any network call.
- **`offlineGrace`** — how long a cached **`valid`** answer may be served *after*it goes stale, but **only when the API is unreachable**. This stops a transient outage from locking out paying customers. Served results carry `_offline => true`.

Persistent caches:

```
use CodeHeaven\License\FileCache;
use CodeHeaven\License\TransientCache;

// Outside WordPress:
new Client($key, ['cache' => new FileCache('/var/cache/myplugin')]);

// Inside WordPress (rides transients / the object cache):
new Client($key, ['cache' => new TransientCache('myplugin_')]);
```

The default is an in-process `ArrayCache` (no cross-request persistence, so no offline grace across requests — supply `FileCache`/`TransientCache` in production).

Custom HTTP transport (WordPress, Guzzle, …)
--------------------------------------------

[](#custom-http-transport-wordpress-guzzle-)

Inject any callable as `http`. It receives `(method, url, headers, ?body)` and must return `['status' => int, 'headers' => array, 'body' => string]`, or throw `TransportException` on a connection failure (which triggers offline grace).

```
new Client($key, [
    'http' => function (string $method, string $url, array $headers, ?string $body): array {
        $res = wp_remote_request($url, compact('method', 'headers', 'body') + ['timeout' => 15]);
        if (is_wp_error($res)) {
            throw new \CodeHeaven\License\TransportException($res->get_error_message());
        }
        return [
            'status'  => (int) wp_remote_retrieve_response_code($res),
            'headers' => wp_remote_retrieve_headers($res)->getAll(),
            'body'    => (string) wp_remote_retrieve_body($res),
        ];
    },
]);
```

See [`examples/gate-plugin.php`](examples/gate-plugin.php) for a complete, fail-safe WordPress gate (validate → activate-on-first-run → admin nag → deactivate-on-uninstall).

Exceptions
----------

[](#exceptions)

All extend `CodeHeaven\License\CodeHeavenException` and expose `->statusCode`, `->apiCode`, `->response`.

ExceptionHTTPWhen`AuthException`401Vendor key missing/invalid (your packaging bug)`LicenseException`403`license_invalid` / `expired` / `domain_not_activated``SeatLimitException`409`seat_limit_exceeded` on `activateDomain()``RateLimitException`429Rate limited (`->retryAfter` holds the hint, if any)`TransportException`—API unreachable and no usable cached result`CodeHeavenException`4xx/5xxAny other non-2xx response> Note: an *invalid* or *expired* license that the API reports with **HTTP 200 and `valid:false`** is returned as data, not thrown. The API only throws `LicenseException` for the 403 cases above.

Development
-----------

[](#development)

```
composer install
composer test      # phpunit
```

License
-------

[](#license)

MIT.

###  Health Score

37

—

LowBetter than 81% of packages

Maintenance100

Actively maintained with recent releases

Popularity0

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity38

Early-stage or recently created project

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Unknown

Total

1

Last Release

5d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/70854483?v=4)[Asker Ali](/maintainers/asker26)[@asker26](https://github.com/asker26)

---

Top Contributors

[![asker26](https://avatars.githubusercontent.com/u/70854483?v=4)](https://github.com/asker26 "asker26 (2 commits)")

---

Tags

wordpresssdklicenselicensingcode-heaven

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/code-heaven-license-sdk/health.svg)

```
[![Health](https://phpackages.com/badges/code-heaven-license-sdk/health.svg)](https://phpackages.com/packages/code-heaven-license-sdk)
```

###  Alternatives

[sybrew/the-seo-framework

An automated, advanced, accessible, unbranded and extremely fast SEO solution for any WordPress website.

47582.8k](/packages/sybrew-the-seo-framework)[mocking-magician/coinbase-pro-sdk

Library for coinbase pro API calls

223.2k](/packages/mocking-magician-coinbase-pro-sdk)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
