dalpras / payment-paypal
PayPal Orders v2 connector for dalpras/payment-core.
Requires
- php: ^8.2
- dalpras/payment-core: dev-main
- psr/http-client: ^1.0
- psr/http-factory: ^1.1
- psr/http-message: ^2.0
Requires (Dev)
- phpunit/phpunit: ^10.0
README
PayPal Orders v2 / Payments v2 connector for dalpras/payment-core.
Supported flow:
- create PayPal order
- redirect buyer to the approval link
- complete checkout by capturing or authorizing the order
- persist PayPal capture and authorization ids as normalized metadata
- capture authorized payments
- refund captured payments
- void authorizations through cancel
- sync order state
- parse and verify webhooks
Installation
composer require dalpras/payment-paypal
Dependencies
dalpras/payment-corepsr/http-clientpsr/http-factorypsr/http-message
Bring your own PSR-18 client and PSR-17 factories.
Basic usage
use DalPraS\Payment\PayPal\Config\PayPalConfig; use DalPraS\Payment\PayPal\Http\PayPalHttpClient; use DalPraS\Payment\PayPal\Mapper\PayPalOrderMapper; use DalPraS\Payment\PayPal\Provider\PayPalProvider; $config = new PayPalConfig( clientId: 'sandbox-client-id', clientSecret: 'sandbox-client-secret', sandbox: true, webhookId: null, brandName: 'My Store', ); $httpClient = new PayPalHttpClient( config: $config, httpClient: $psr18Client, requestFactory: $requestFactory, streamFactory: $streamFactory, ); $provider = new PayPalProvider( config: $config, httpClient: $httpClient, mapper: new PayPalOrderMapper(), );
Register the provider in PaymentManager through the core ProviderRegistry.
Checkout mapping
CheckoutRequest maps to POST /v2/checkout/orders.
| Core field | PayPal field |
|---|---|
intent = sale |
intent = CAPTURE |
intent = authorize / capture_later |
intent = AUTHORIZE |
| line items | purchase_units[0].items |
| amount breakdown | purchase_units[0].amount.breakdown |
paymentReference |
purchase_units[0].custom_id |
| return/cancel URLs | payment_source.paypal.experience_context |
| locale | payment_source.paypal.experience_context.locale |
| idempotency key | PayPal-Request-Id |
Metadata returned by this provider
Checkout creation
[
'provider' => 'paypal',
'provider_payment_id' => $paypalOrderId,
'order_id' => $paypalOrderId,
'paypal_order_id' => $paypalOrderId,
]
Completion / authorization / sync
The provider extracts capture and authorization ids from PayPal order payloads:
[
'provider' => 'paypal',
'provider_payment_id' => $paypalOrderId,
'order_id' => $paypalOrderId,
'paypal_order_id' => $paypalOrderId,
'capture_id' => $captureId,
'paypal_capture_id' => $captureId,
'authorization_id' => $authorizationId,
'paypal_authorization_id' => $authorizationId,
]
Core stores these values and reuses them for future refund/capture/cancel operations.
Completion
completeCheckout() resolves the PayPal order id from:
expectedProviderPaymentIdqueryParams['token']bodyParams['token']metadata['paypal_order_id']metadata['order_id']
Then it chooses the final action from expectedIntent:
sale-> capture the orderauthorize/capture_later-> authorize the order
When used through PaymentManager, expectedProviderPaymentId, expectedIntent and metadata are normally filled automatically from the stored Payment.
Refunds
Refunds use POST /v2/payments/captures/{capture_id}/refund.
The provider resolves the capture id from:
metadata['capture_id']metadata['paypal_capture_id']providerPaymentId
Full refund:
$result = $paymentManager->refund(new RefundRequest( providerCode: 'paypal', paymentReference: $paymentReference, providerPaymentId: null, idempotencyKey: $refundId, metadata: [ 'description' => 'Customer refund', ], ));
Partial refund:
$result = $paymentManager->refund(new RefundRequest( providerCode: 'paypal', paymentReference: $paymentReference, providerPaymentId: null, idempotencyKey: $refundId, metadata: [ 'amount_decimal' => '50.00', 'currency' => 'EUR', 'description' => 'Partial refund', ], ));
Capturing authorized payments
Captures use POST /v2/payments/authorizations/{authorization_id}/capture when an authorization id is available.
$result = $paymentManager->capture(new CaptureRequest( providerCode: 'paypal', paymentReference: $paymentReference, providerPaymentId: null, idempotencyKey: $captureId, metadata: [ 'amount_decimal' => '50.00', 'currency' => 'EUR', 'description' => 'Capture authorized amount', 'final_capture' => true, ], ));
Cancelling / voiding authorizations
cancel() voids an authorization when authorization_id or paypal_authorization_id is available. Through PaymentManager, that metadata is normally reused from completion/authorization.
$result = $paymentManager->cancel(new CancelRequest( providerCode: 'paypal', paymentReference: $paymentReference, providerPaymentId: null, idempotencyKey: $voidId, metadata: [ 'description' => 'Customer cancelled before capture', ], ));
Webhook verification
The provider builds PayPal's webhook verification payload from incoming headers and the configured webhook id. Configure webhookId in PayPalConfig before using verifyWebhook() in production.
Testing
composer install vendor/bin/phpunit
Syntax check:
find src tests -name '*.php' -print0 | xargs -0 -n1 php -l
License
MIT