paysera/lib-checkout-integration-sdk

Paysera PHP checkout integration SDK

Maintainers

Package info

github.com/paysera/lib-checkout-integration-sdk

Documentation

pkg:composer/paysera/lib-checkout-integration-sdk

Transparency log

Statistics

Installs: 0

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

2.3.0 2026-07-17 11:05 UTC

This package is auto-updated.

Last update: 2026-07-28 07:11:54 UTC


README

Packagist Version Packagist Downloads License: LGPL-3.0-or-later

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-curl
  • ext-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_check fallback 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\CachePool wrapping 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 CurlHttpClient already sets CURLOPT_CONNECTTIMEOUT=10 and CURLOPT_TIMEOUT=30.
  • Symfony HttpClient: HttpClient::create(['timeout' => 10, 'max_duration' => 10]).
  • Guzzle: new Client(['connect_timeout' => 5, 'timeout' => 10]).

Documentation

Use Cases

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.