> For the complete documentation index, see [llms.txt](https://developer.paddle.com/llms.txt).

# Get started with Paddle in PHP

Install the Paddle PHP SDK, initialize a client, make your first request, and verify webhook signatures.

---

{% version-badge sdk="paddle-php" /%}

This quickstart walks through installing the Paddle PHP SDK, initializing a client, making your first read-only API call, and verifying webhook signatures.

{% callout type="note" %}
**Using Laravel?** Use [Laravel Cashier Paddle](https://laravel.com/docs/cashier-paddle) — it's maintained by the Laravel team and wraps this SDK with framework-native conventions for billing, subscriptions, and the customer portal.
{% /callout %}

## Before you begin

- A [Paddle sandbox account](https://developer.paddle.com/sdks/sandbox.md).
- An [API key](https://developer.paddle.com/api-reference/about/api-keys#create-api-key.md) generated in your sandbox dashboard.
- PHP 8.1 or later, with [Composer](https://getcomposer.org/) installed.

## 1. Install the SDK {% step=true %}

Install `paddlehq/paddle-php-sdk` with Composer:

```sh
composer require paddlehq/paddle-php-sdk
```

## 2. Initialize the client {% step=true %}

Create a `Client` with your API key. Use the `SANDBOX` environment while you're building.

```php
use Paddle\SDK\Client;
use Paddle\SDK\Environment;
use Paddle\SDK\Options;

$paddle = new Client(
    apiKey: getenv('PADDLE_API_KEY'),
    options: new Options(Environment::SANDBOX),
);
```

For production, drop the `options` argument:

```php
$paddle = new Client(getenv('PADDLE_API_KEY'));
```

{% callout type="note" %}
Sandbox API keys contain `_sdbx`. Sandbox and live keys are separate — using one against the other API returns a `forbidden` error.
{% /callout %}

## 3. Make your first request {% step=true %}

List products to confirm the client is wired up. The SDK returns an iterable that paginates automatically.

```php
use Paddle\SDK\Client;
use Paddle\SDK\Environment;
use Paddle\SDK\Options;
use Paddle\SDK\Exceptions\ApiError;

$paddle = new Client(
    apiKey: getenv('PADDLE_API_KEY'),
    options: new Options(Environment::SANDBOX),
);

try {
    $products = $paddle->products->list();
    foreach ($products as $product) {
        echo $product->id . '  ' . $product->name . PHP_EOL;
    }
} catch (ApiError $error) {
    echo 'Paddle API error: ' . $error->getMessage();
}
```

If your sandbox account is empty, the loop runs zero times — that's fine. Create a product in the dashboard or via `$paddle->products->create()` to see results.

## 4. Verify webhooks {% step=true %}

Paddle pushes webhook events to your endpoint when subscriptions, transactions, and customers change state. The SDK's `Verifier` accepts any [PSR-7](https://www.php-fig.org/psr/psr-7/) `RequestInterface` — Guzzle, Symfony, Laravel (`Illuminate\Http\Request::toPsrRequest()`), and most modern PHP HTTP frameworks all support this.

Always verify the signature before acting on the payload.

```php
use GuzzleHttp\Psr7\ServerRequest;
use Paddle\SDK\Entities\Event;
use Paddle\SDK\Notifications\Secret;
use Paddle\SDK\Notifications\Verifier;

$request = ServerRequest::fromGlobals();
$secret = new Secret(getenv('PADDLE_WEBHOOK_SECRET'));

if (!(new Verifier())->verify($request, $secret)) {
    http_response_code(400);
    exit('invalid signature');
}

$event = Event::fromRequest($request);

switch ($event->eventType) {
    case 'transaction.completed':
        // Provision access, send a receipt, etc.
        break;
    case 'subscription.updated':
        // Sync the subscription to your database.
        break;
}

http_response_code(200);
echo 'ok';
```

For the full webhook setup flow — creating notification destinations, picking events, retry behavior — see [Verify webhook signatures](https://developer.paddle.com/webhooks/signature-verification.md).

## Next steps

{% card-group cols=2 %}
{% card title="Build with subscriptions" icon="carbon:repeat" url="/build/subscriptions" %}
Lifecycle, plan changes, pause and resume, addons.
{% /card %}
{% card title="Set up notification destinations" icon="carbon:notification" url="/webhooks/notification-destinations" %}
Configure where Paddle sends webhook events.
{% /card %}
{% card title="API reference" icon="carbon:api" url="/api-reference/overview" %}
Browse every endpoint Paddle exposes.
{% /card %}
{% card title="PHP SDK reference" icon="php" url="/sdks/libraries/php" %}
Full SDK reference — version, repo, install, auth.
{% /card %}
{% /card-group %}

{% callout type="note" %}
**Working with Laravel?** [Cashier Paddle](https://laravel.com/docs/cashier-paddle) is the recommended path. It uses this SDK under the hood and adds Eloquent-friendly billing primitives, middleware, and Blade components.
{% /callout %}