paypal/paypal-server-sdk
Official PayPal Server SDK for PHP. Integrates with a limited set of PayPal REST APIs (Orders, Payments, Vault, Transaction Search, Subscriptions). Supports sandbox/live environments, configurable timeouts, and optional retries/backoff.
Install the SDK via Composer:
composer require "paypal/paypal-server-sdk:2.2.0"
Note: This SDK is small (51 stars, low activity), mature enough for basic use, but not actively developed (last update 2022). Consider if newer alternatives (e.g., PayPal's official paypal/rest-api-sdk-php or direct API calls) better suit long-term needs.
Initialize the client with credentials and environment:
use PaypalServerSdkLib\PaypalServerSdkClientBuilder;
use PaypalServerSdkLib\Environment;
use PaypalServerSdkLib\Authentication\ClientCredentialsAuthCredentialsBuilder;
$client = PaypalServerSdkClientBuilder::init()
->clientCredentialsAuthCredentials(
ClientCredentialsAuthCredentialsBuilder::init(
$paypalClientId,
$paypalClientSecret
)
)
->environment(Environment::SANDBOX)
->build();
First use case: Create an order (v2 Orders API) for a simple checkout:
$createOrderRequest = new CreateOrderRequest();
$createOrderRequest->intent = 'CAPTURE';
$createOrderRequest->purchaseUnits = [/* your amount, description, etc. */];
$response = $client->getOrdersController()->createOrder($createOrderRequest);
$orderId = $response->getId();
Inject the client as a service (e.g., in Laravel):
Define a singleton in App\Providers\AppServiceProvider@register():
$this->app->singleton(\PaypalServerSdkLib\PaypalServerSdkClient::class, function ($app) {
return PaypalServerSdkClientBuilder::init()
->clientCredentialsAuthCredentials(
ClientCredentialsAuthCredentialsBuilder::init(
config('services.paypal.client_id'),
config('services.paypal.client_secret')
)
)
->environment(config('app.env') === 'production' ? Environment::PRODUCTION : Environment::SANDBOX)
->build();
});
For transactions (e.g., capture an order):
$captureRequest = new CaptureOrderRequest();
$response = $client->getOrdersController()->captureOrder($orderId, $captureRequest);
Vault usage (US only): Store payment cards or PayPal accounts for future subscriptions/payments:
$response = $client->getVaultController()->createPaymentToken([
'type' => 'CARD',
'card' => new CardRequest([...]),
]);
$paymentTokenId = $response->getId();
Handle webhooks separately: This SDK does not validate or parse webhooks. Use the raw payload + PayPal's webhook verification endpoint manually.
Batch requests: Use the SDK’s generated controllers for simple CRUD, but avoid complex orchestration. For multi-step flows (create → authorize → capture), wrap calls in atomic jobs/transactions.
Logging & retries: Enable useful defaults:
->loggingConfiguration(
LoggingConfigurationBuilder::init()
->level(LogLevel::DEBUG)
->requestConfiguration(RequestLoggingConfigurationBuilder::init()->body(true))
->responseConfiguration(ResponseLoggingConfigurationBuilder::init()->body(true))
)
->enableRetries(true)
->maximumRetryWaitTime(30)
Heavily limited endpoint coverage: Only 5 controllers. No support for newer PayPal APIs like v2/checkout/orders with PFWO (PayPal Checkout with PayPal wallets) or Smart Payment Buttons features beyond basic Orders/Payments. Always cross-check with PayPal’s public docs before implementation.
Auth is client-credentials only (machine-to-machine). If your app needs user-based OAuth (e.g., via browser redirect), this SDK cannot help — you’ll need to implement your own OAuth flow and use direct API calls or a different SDK.
Hardcoded timeout & retry defaults: Default timeout=0 (infinite) can hang workers. Always set explicit timeouts (e.g., ->timeout(10)), especially in queues/cli.
No model mutators or validation: SDK uses raw DTOs (e.g., OrderRequest). Passing invalid objects (e.g., missing required purchaseUnits.amount) causes HTTP 400/500 — validate before calling SDK methods.
Case sensitivity matters: Enum values like payment_initiator must match exact allowed strings (e.g., "CUSTOMER" not "customer"). Check model docs rigorously.
Sandbox environment ≠ Production parity: Some features (e.g., Vault) behave differently or may be disabled in sandbox. Test thoroughly.
Missing Laravel integration: No service provider or config stubs — you must configure manually (e.g., via .env and config/services.php). Avoid storing secrets directly in code.
Deprecation warnings: Some models (e.g., PaypalWalletStoredCredential) flag fields like chargePattern as deprecated — prefer usagePattern. Keep an eye on changelog.
No PSR-18 HTTP client injection: Internals use Guzzle 6+, which may conflict with modern Laravel apps using PSR-18. Check guzzlehttp/guzzle version compatibility.
Error handling: All SDK calls throw \PaypalServerSdkLib\Exceptions\ApiException or subclasses. Always wrap calls in try/catch and parse body for PayPal-specific error codes (e.g., ORDER_NOT_APPROVED).
How can I help you explore Laravel packages today?