This quickstart walks through installing the Paddle PHP SDK, initializing a client, making your first read-only API call, and verifying webhook signatures.
Using Laravel?
Use Laravel Cashier Paddle instead. It's maintained by the Laravel team and comes with framework-native conventions for payments, billing, and subscriptions.
Before you begin
You'll need:
- A Paddle sandbox account.
- A sandbox API key with permission to read and write products.
- PHP 8.1 or later, with Composer installed.
Install the SDK
Install paddlehq/paddle-php-sdk with Composer:
composer require paddlehq/paddle-php-sdkView the PHP SDK on GitHub
Initialize the client
Create a Client with your API key. Use the SANDBOX environment while you're building.
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:
$paddle = new Client(getenv('PADDLE_API_KEY'));Sandbox API keys contain _sdbx. Sandbox and live keys are separate — using one against the other API returns a forbidden error.
Make your first request
List products to confirm the client is wired up. The SDK returns an iterable that paginates automatically.
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. Create a product in the dashboard or via $paddle->products->create() to see results.
4. Verify webhooks
You can use webhooks to keep your app in sync with Paddle. For example, you can provision access when a subscription is created, or revoke access when a subscription is cancelled.
The SDK's Verifier accepts any PSR-7 RequestInterface, like 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.
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, including creating notification destinations, picking events, and retry behavior, see Verify webhook signatures.
Next steps
- Explore Laravel Cashier Paddle for a Laravel-native way to build with Paddle.
- Use the webhook simulator to test webhook events.
- Browse the API reference to see every endpoint Paddle exposes.
- View the PHP SDK reference for the full SDK reference.