PHP SDK
PHP SDK
Pure PHP 8.0+ client. Enable ext-curl and ext-json for online calls, and ext-openssl for offline verification. No Guzzle, no additional packages. Works with Laravel, Symfony, WordPress plugins, raw PHP scripts.
Download PHP SDK (ZIP)Installation via Composer
composer require permitcore/sdk
Or install from the downloaded source ZIP:
unzip permitcore-sdk-php.zip -d permitcore-sdk-php
# Then in composer.json add the path repository:
composer config repositories.local path ../permitcore-sdk-php
composer require permitcore/sdk:@dev
Quick start — validate
<?php
require 'vendor/autoload.php';
use PermitCore\PermitCoreClient;
$client = new PermitCoreClient('https://api.permitcore.dev');
$result = $client->validate(
'PERMIT-XXXX-XXXX-XXXX-XXXX',
expectedProductId: '7f3e9a2b-1c4d-4e8f-9a6b-3d2c1e0f5a8b' // Optional — reject a key issued for a different product instead of silently accepting it
);
if ($result->isValid) {
echo 'Valid! Product: ' . $result->productName . ' (' . $result->productId . ')' . PHP_EOL;
if ($result->hasFeature('export')) {
enableExport();
}
} elseif ($result->errorCode === 'WrongProduct') {
exit('This key is for a different product: ' . $result->productId);
} else {
exit('License invalid: ' . $result->message);
}
Activate (call once per installation)
$result = $client->activate(
licenseKey: 'PERMIT-XXXX-XXXX-XXXX-XXXX',
deviceId: null, // auto-generated HWID
deviceName: 'Production Server',
expectedProductId: '7f3e9a2b-1c4d-4e8f-9a6b-3d2c1e0f5a8b' // optional
);
if ($result->errorCode === 'WrongProduct') {
exit('This key is for a different product: ' . $result->productId);
}
if (!$result->isValid) {
exit('Activation failed: ' . $result->message);
}
// Save $result->isValid to local storage — use validate() on every subsequent launch.
Metered billing
// Record a single event
$client->meter('PERMIT-XXXX-XXXX-XXXX-XXXX', 'api_call');
// Record bulk usage with metadata
$client->meter(
licenseKey: 'PERMIT-XXXX-XXXX-XXXX-XXXX',
eventName: 'export',
quantity: 5,
meta: ['format' => 'pdf', 'pages' => 12]
);
Floating licenses
// Check out a seat at session start
$session = $client->checkout('PERMIT-XXXX-XXXX-XXXX-XXXX');
if (!$session->success) {
exit('No seats available: ' . $session->message);
}
$token = $session->sessionToken;
// Heartbeat every 4–5 minutes (use a cron job or event loop)
$client->heartbeat($token);
// Release when the user logs out or the session ends
$client->checkin($token);
Offline grace period
$result = $client->validate($licenseKey); // falls back to disk cache automatically
if ($result->isOffline) {
// Running on cached result — server unreachable
showNotice('Running offline. Connect to refresh your license.');
}
LicenseResult properties
| Property | Type | Description |
|---|---|---|
isValid | bool | True if the license is active and valid |
productName | ?string | Product the license belongs to |
remainingActivations | ?int | Activation slots remaining |
expiresAt | ?string | ISO 8601 expiry date, null = perpetual |
features | ?array | Feature flag list, e.g. ['export','api'] |
isTrial | bool | True for trial licenses |
trialDaysRemaining | ?int | Days until trial expires |
nodeLocked | bool | True if bound to a specific device |
offlineGraceDays | ?int | How many days the cache remains valid |
minVersion | ?string | Minimum app version the license allows |
maxVersion | ?string | Maximum app version the license allows |
vendorWarning | ?string | Non-fatal message from the vendor |
message | ?string | Reason when isValid = false |
isOffline | bool | True when result came from local cache |
productId | ?string | Stable ID of the product this license belongs to. Always present when a license was found, even without passing expectedProductId. |
hasFeature(string $feature): bool — case-insensitive check whether a feature flag is present on the license.
Product scoping: by default, any active key belonging to your tenant validates/activates successfully regardless of which product it was issued for. If you sell more than one product, either check $result->productId yourself, or pass the optional $expectedProductId parameter and let the server reject a mismatch ($result->errorCode === 'WrongProduct'). Find a product's ID in the Admin panel under Products.