PHP SDK
Backend PHP SDK setup with Composer and Packagist.
Use perkamo/sdk from trusted PHP backends. Do not expose Perkamo server API keys to browser or mobile code.
Install
bash
composer require perkamo/sdkCreate a client
php
use Perkamo\Client;
$perkamo = new Client(
apiKey: getenv('PERKAMO_SECRET_KEY'),
);The PHP SDK defaults to the hosted Perkamo API. Pass baseUrl only when Perkamo support supplies a different API URL.
Identify a customer
Use your application's stable user id as the Perkamo customer id. Send e-mail, name and internal customer metadata as trusted customer traits from backend code:
php
$perkamo->identify('customer_123', [
'email' => 'customer@example.test',
'name' => 'Customer Test',
'crm_id' => 'crm_123',
]);Only send non-secret facts your application is allowed to share with Perkamo. Calling identify() again updates traits for the same customer.
Emit one event
php
use Perkamo\EventInput;
$event = EventInput::create('customer_123', 'purchase.completed')
->withTransactionId('order_1092')
->withContextValue('order_id', 'order_1092')
->withContextValue('amount', 12900)
->withContextValue('currency', 'CZK');
$result = $perkamo->emitEvent($event);
if ($result->applied) {
foreach ($result->delta as $delta) {
printf("%+g %s\n", $delta->amount, $delta->wallet);
}
}Use stable business ids as transaction ids for retriable events. For example, use an order id for checkout events or a lesson id plus user id for learning progress events.
For simple one-off events, emit() remains available and builds the same typed event internally:
php
$result = $perkamo->emit(
userId: 'customer_123',
event: 'purchase.completed',
context: ['order_id' => 'order_1092'],
transactionId: 'order_1092',
);Both emitEvent() and emit() return Perkamo\EventIngestResult, with typed properties such as $result->applied, $result->delta, $result->walletState, $result->level and toArray() for the raw API payload.
Read the event catalog
Use program() or eventCatalog() from trusted backend code when an internal admin tool needs configured event keys and labels:
php
$events = $perkamo->eventCatalog();
foreach ($events as $event) {
printf("%s\n", $event['event']);
}program() returns the active Space program blueprint, metrics and usage summary. Do not treat either method as a wallet editing API.
Handle API errors
Non-2xx responses throw Perkamo\Exception\PerkamoApiException with the HTTP status, parsed body and operational metadata when available:
php
use Perkamo\Exception\PerkamoApiException;
try {
$perkamo->emit('customer_123', 'purchase.completed', transactionId: 'order_1092');
} catch (PerkamoApiException $error) {
error_log(json_encode([
'status' => $error->statusCode(),
'request_id' => $error->requestId(),
'retry_after' => $error->retryAfter(),
'rate_limit' => $error->rateLimit(),
]));
}Create a client token
Authenticate the user in your PHP backend first, then sign a short-lived client token for the browser SDK.
Create the signing key in the Perkamo console under Settings → Security → Signing keys. It gives you a KID (shown in the creation dialog and then listed in the table) and a one-time secret (shown once, backend-only). Read both from environment variables — the names are your own choice:
php
use Perkamo\ClientTokenSigner;
$token = ClientTokenSigner::sign(
kid: getenv('PERKAMO_SIGNING_KID'), // KID
secret: getenv('PERKAMO_SIGNING_SECRET'), // one-time secret, backend-only
subject: 'customer_123',
scope: ['customer:read', 'events:write'],
events: ['page.viewed'],
ttlSeconds: 600,
);
return new JsonResponse([
'token' => $token,
'token_type' => 'Bearer',
]);| Argument | What it is |
|---|---|
kid | KID of your signing key; goes in the token header. Safe to expose. |
secret | The signing key's one-time secret that signs the token. Sensitive — backend-only. |
subject | The user the token authorizes — your stable user id. |
scope | Client permissions: customer:read, events:write, stream:read. |
events | Optional allow-list of event names the token may emit. |
ttlSeconds | Token lifetime in seconds (default 600). Clamped to the key's maximum at verify. |
Only the secret is sensitive; the kid is public and travels in every token header. scope and events are clamped to the signing key policy during verification. Use any secret manager in place of getenv().
Validate the integration
Use Events to confirm emitted events and Customers to inspect customer state after rules apply.
Symfony applications that need both backend event emission and browser SDK token endpoints can use Symfony Bundle.