SDKsStable · 3 min read

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/sdk

Create 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',
]);
ArgumentWhat it is
kidKID of your signing key; goes in the token header. Safe to expose.
secretThe signing key's one-time secret that signs the token. Sensitive — backend-only.
subjectThe user the token authorizes — your stable user id.
scopeClient permissions: customer:read, events:write, stream:read.
eventsOptional allow-list of event names the token may emit.
ttlSecondsToken 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.