PHP SDK

Integrate Perly churn prevention into your Laravel application with a service provider, middleware, and user resolver.

perly/perly-phpv1.0.05 minutes

Installation

composer require perly/perly-php

Publish the configuration file:

php artisan vendor:publish --tag=perly-config

Usage

Set your API key in the published config file and register the middleware.

// config/perly.php
return [
    'api_key' => env('PERLY_API_KEY'),
];
// app/Http/Kernel.php
protected $middlewareGroups = [
    'api' => [
        \Perly\Http\PerlyMiddleware::class,
    ],
];

Bind the user resolver in your service provider:

// app/Providers/AppServiceProvider.php
use Perly\Contracts\PerlyUserResolver;
use App\Perly\AppPerlyUserResolver;

public function register()
{
    $this->app->bind(PerlyUserResolver::class, AppPerlyUserResolver::class);
}

User Resolver

Create a resolver class that implements PerlyUserResolver. The resolve method receives the Laravel request and returns a Perly user.

// app/Perly/AppPerlyUserResolver.php
namespace App\Perly;

use Perly\Contracts\PerlyUserResolver;
use Perly\PerlyBuilder;
use Illuminate\Http\Request;

class AppPerlyUserResolver implements PerlyUserResolver
{
    public function resolve(Request $request)
    {
        $user = $request->user();
        if (!$user) {
            return null;
        }

        return PerlyBuilder::create()
            ->setId($user->id)
            ->setMetadata([
                'plan' => $user->plan,
                'region' => $user->region,
                'company_id' => $user->company_id,
            ])
            ->linkStripeById($user->stripe_customer_id)
            ->linkHubspotById($user->hubspot_contact_id)
            ->build();
    }
}

Tracking Events

Use the Perly facade anywhere in your Laravel application to track customer events.

use Perly\Facades\Perly;

// In a controller
class OnboardingController extends Controller
{
    public function complete(Request $request)
    {
        Perly::track($request->user()->id, 'onboarding_completed');
        return response()->json(['success' => true]);
    }

    public function exportReport(Request $request)
    {
        Perly::track($request->user()->id, 'report_exported', [
            'format' => $request->input('format'),
        ]);
        return response()->download($reportPath);
    }

    public function inviteTeamMember(Request $request)
    {
        Perly::track($request->user()->id, 'team_member_invited', [
            'email' => $request->input('email'),
        ]);
        return response()->json(['invited' => true]);
    }
}

Expansion Signals

Send signals when customers approach usage limits to drive upsell workflows.

use Perly\Facades\Perly;

// In a service or job
class UsageCheckService
{
    public function checkSeatLimit(User $user): void
    {
        $seats = $user->company->members()->count();
        $limit = $user->company->seat_limit;

        if ($seats > $limit * 0.9) {
            Perly::signal($user->id, 'seat_limit_near', [
                'current' => $seats,
                'limit' => $limit,
            ]);
        }
    }
}

// Other signal types
Perly::signal($userId, 'api_usage_high', ['current' => 9500, 'limit' => 10000]);
Perly::signal($userId, 'rate_limit_hit', ['endpoint' => '/api/search']);
Perly::signal($userId, 'storage_limit_near', ['used_gb' => 9.2, 'limit_gb' => 10]);
Perly::signal($userId, 'billing_retry_failed', ['attempt' => 3]);