PHP SDK

Official SDKs

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

PropertyTypeDescription
isValidboolTrue if the license is active and valid
productName?stringProduct the license belongs to
remainingActivations?intActivation slots remaining
expiresAt?stringISO 8601 expiry date, null = perpetual
features?arrayFeature flag list, e.g. ['export','api']
isTrialboolTrue for trial licenses
trialDaysRemaining?intDays until trial expires
nodeLockedboolTrue if bound to a specific device
offlineGraceDays?intHow many days the cache remains valid
minVersion?stringMinimum app version the license allows
maxVersion?stringMaximum app version the license allows
vendorWarning?stringNon-fatal message from the vendor
message?stringReason when isValid = false
isOfflineboolTrue when result came from local cache
productId?stringStable 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.