paysera / lib-checkout-integration-sdk
Paysera PHP checkout integration SDK
Package info
github.com/paysera/lib-checkout-integration-sdk
pkg:composer/paysera/lib-checkout-integration-sdk
Requires
- php: ^7.4 || ^8.0
- ext-curl: *
- ext-json: *
- fig/http-message-util: ^1.1
- firebase/php-jwt: ^6.10 || ^7.0
- nyholm/psr7: ^1.8
- php-http/client-common: ^2.7
- php-http/curl-client: ^2.3
- php-http/logger-plugin: ^1.3 || ^1.4
- php-http/message: ^1.16
- psr/cache: ^1.0 || ^2.0 || ^3.0
- psr/clock: ^1.0
- psr/container: ^1.1 || ^2.0
- psr/log: ^1.1 || ^3.0
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.70
- php-http/mock-client: ^1.6
- phpstan/extension-installer: ^1.4
- phpstan/phpstan-deprecation-rules: ^2.0
- phpstan/phpstan-phpunit: ^2.0
- phpstan/phpstan-strict-rules: ^2.0
- phpunit/phpunit: ^9.6
This package is auto-updated.
Last update: 2026-07-28 07:11:54 UTC
README
Paysera PHP SDK for integrating with the Paysera Checkout v3 API: payment initiation, callback verification, refunds, project eligibility, and localization — with a single SdkFacade entry point.
Supported PHP versions
PHP 7.4, 8.0, 8.1, 8.2, 8.3, and 8.4. The minimum requirement is declared in composer.json as ^7.4 || ^8.0.
Requirements
- PHP 7.4 or higher
ext-curlext-json
Installation
Install via Composer:
composer require paysera/lib-checkout-integration-sdk
Obtaining sandbox credentials
A sandbox project with API credentials is required to run the SDK end to end. Self-service onboarding for external integrators is documented on the Paysera developer portal at https://developers.paysera.com.
Code style
PSR-12. Built on top of PSR standards (PSR-3 logging, PSR-6 cache, PSR-18 HTTP client, PSR-20 clock).
Features
- JWT Token Validation: Automatic validation of JWT tokens with project ID extraction
- PSR-Compliant Caching: Configurable cache pool for improved performance
- Payment Processing: Full payment order creation and link generation
- Callback Processing: Secure webhook verification and processing
- Project Eligibility: Single-call eligibility check that combines payment-collection status and store-URL verification, with deterministic
failed_to_checkfallback for retry UX - Translations: Namespace-based localization with SDK and plugin translation merging
- Multiple Environments: Support for both production and sandbox environments
Quick Start
<?php use Paysera\CheckoutSdk\SdkFacadeBuilder; use Paysera\CheckoutSdk\Entity\PaymentApiCredentials; // Build SDK facade with minimal configuration $sdkFacade = (new SdkFacadeBuilder()) ->build() ; // Authorize with your API credentials $apiCredentials = new PaymentApiCredentials( 'your-client-id', 'your-client-secret' ); $sdkFacade ->getAuthorizationFacade() ->authorize($apiCredentials) ; // Now you're ready to process payments
SDK Facade Configuration
The SDK facade can be customized with various options:
<?php use Paysera\CheckoutSdk\SdkFacadeBuilder; $sdkFacade = (new SdkFacadeBuilder()) // Optional: Set custom PSR-3 logger. NullLogger by default ->setLogger($logger) // Optional: Set custom PSR-18 HTTP client. CurlHttpClient by default ->setHttpClient($httpClient) // Optional: Set custom PSR-6 cache pool. InMemoryCache by default. // Caches Keycloak JWKS used for JWT signature verification. // Persistent pool (Redis/APCu/filesystem) is strongly recommended in // production — see "JWKS cache" section below. ->setCacheItemPool($cacheItemPool) // Optional: Set custom PSR-20 clock. System clock by default // Used for time-based operations like token expiration ->setClock($clock) // Optional: Set auth token repository. InMemoryRepository by default // Permanently stores payment API access tokens // Needed for using the same token between requests ->setPaymentApiAuthTokenRepository($paymentApiAuthTokenRepository) // Optional: Set credentials repository. InMemoryRepository by default // Permanently stores payment API credentials // Needed for automatically refreshing tokens ->setPaymentApiCredentialsRepository($paymentApiCredentialsRepository) // Optional: Set custom API client formatter. SecureApiClientFormatter by default // Controls how HTTP requests/responses are formatted in logs ->setApiClientFormatter($apiClientFormatter) ->build() ;
JWKS cache
The SDK verifies JWT access token signatures against Keycloak's JWKS
endpoint (/auth/realms/Paysera/protocol/openid-connect/certs). The key
set is fetched once on cold start and cached for 30 days. The endpoint is
re-contacted only when an incoming JWT carries a kid that is not present
in the cached set (Keycloak key rotation).
To benefit from this strategy in production you must inject a
persistent PSR-6 cache pool via setCacheItemPool(). The default
InMemoryCache is scoped to a single PHP request and defeats the caching
completely in shared-nothing deployments (PHP-FPM, multi-container setups),
causing a /certs fetch on every validation.
Recommended backends: Redis, APCu, filesystem cache — anything that survives across PHP request lifecycles. Examples:
- Symfony:
Symfony\Component\Cache\Adapter\RedisAdapter - Laravel:
Illuminate\Cache\Psr6\CachePoolwrapping the application cache - WordPress/WooCommerce: any plugin bridging WP transients or object cache to PSR-6
- Plain PHP:
Symfony\Component\Cache\Adapter\FilesystemAdapter
If /certs is unreachable during a rotation fallback, JWT validation
fails loudly — the SDK never accepts an unsigned or unverifiable token.
Forcing a JWKS refresh
Normal Keycloak rotation is handled automatically via the unknown-kid
fallback. For incident response (revoked or compromised signing key),
the cached key set must be purged from the PSR-6 pool so the next JWT
validation cold-starts it from /certs again.
Firebase\JWT\CachedKeySet stores its entries under the jwks prefix,
but setCacheKeys() SHA-256-hashes the composite key whenever it exceeds
64 characters — and every real Paysera JWKS URL crosses that threshold.
The prefix is lost in the final storage key, which means a
redis-cli --scan --pattern 'jwks*' sweep will not match anything.
The reliable approach is to dedicate an isolated PSR-6 pool to the SDK and clear it as a whole during an incident:
- Dedicated Redis DB:
redis-cli -n <sdk-db-index> FLUSHDB - Symfony Cache (dedicated pool):
bin/console cache:pool:clear <paysera-sdk-pool> - Dedicated filesystem cache: delete the cache directory
(
rm -rf var/cache/paysera-sdk/*) and reload the PHP-FPM pool - APCu:
apcu_clear_cache()only if APCu is not shared with unrelated application data; otherwise prefer a different backend
Sharing the SDK's PSR-6 pool with unrelated application caches defeats this procedure — a full flush would also wipe business data. Keep the pool SDK-scoped so incident response stays a one-liner.
HTTP client timeouts
JWKS fetches go through the PSR-18 client injected via setHttpClient()
(or the default CurlHttpClient otherwise). During cold start and
rotation fallback, the call blocks the caller thread. A slow or
unreachable /certs endpoint with an unbounded client timeout turns
every such call into a hung checkout request.
Required for production: configure a finite connect timeout (~5 s) and total-request timeout (~10 s) on the injected PSR-18 client.
- The default
CurlHttpClientalready setsCURLOPT_CONNECTTIMEOUT=10andCURLOPT_TIMEOUT=30. - Symfony HttpClient:
HttpClient::create(['timeout' => 10, 'max_duration' => 10]). - Guzzle:
new Client(['connect_timeout' => 5, 'timeout' => 10]).
Documentation
Use Cases
- Authorization - Authenticate with the Payment API and decode JWT tokens
- Payment Initiation - Create payment orders and generate payment links
- Callback Processing - Securely process payment webhooks
- Project Eligibility - Check whether the current store is allowed to collect payments
- Merchant Area Deeplinks - Build project-specific Merchant Area URLs from the stored token
- Translations - Localization with SDK and plugin namespace support
- Payment Method Logos - Logo URLs provided by the API via
PaymentMethod::getLogoUrl() - Local Development - Setup and testing in development environment
Version History
See CHANGELOG.md for detailed version history and upgrade notes.
Contributing
See CONTRIBUTING.md. Paysera GitLab is the source of truth; the GitHub repository is a read-only mirror updated on every release tag.
Security
Vulnerabilities should be reported privately — see SECURITY.md. Please do not open public issues for security findings.
License
LGPL-3.0-or-later. The full license text is in LICENSE.