Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Przelewy24 Php Laravel Package

mnastalski/przelewy24-php

Przelewy24 payment gateway integration for PHP and Laravel. Register transactions, verify payments, handle webhooks, and manage refunds through a clean API, making Polish online payments easier to add to your application.

Deep Wiki
Context7

Getting Started

This is a framework-agnostic SDK, not a Laravel package — there is no auto-discovery, no service provider, and no facade. Plan on writing ~30 lines of glue code the first time and reusing it everywhere after.

Minimal setup:

composer require mnastalski/przelewy24-php
  1. Get credentials from the Przelewy24 merchant panel: merchantId (posId), crc key, apiKey (for REST auth), and reportKey. Sandbox credentials are separate and issued from sandbox.przelewy24.pl.
  2. Add config in config/services.php:
'przelewy24' => [
    'merchant_id' => env('P24_MERCHANT_ID'),
    'crc'         => env('P24_CRC'),
    'api_key'     => env('P24_API_KEY'),
    'report_key'  => env('P24_REPORT_KEY'),
    'sandbox'     => env('P24_SANDBOX', true),
],
  1. Bind a singleton in AppServiceProvider::register():
$this->app->singleton(Client::class, fn ($app) => new Client(
    config('services.przelewy24.merchant_id'),
    config('services.przelewy24.crc'),
    config('services.przelewy24.api_key'),
    config('services.przelewy24.report_key'),
    config('services.przelewy24.sandbox'),
));
  1. First use case: create an Order, call the SDK's transaction registration, persist the returned token, and redirect the user to the P24 payment URL. The notification/return flow is where most integration bugs live, so build the webhook handler at the same time rather than later.

Where to look first in the repo: the README.md (short but the only usage reference), then src/Client.php and the resource classes it exposes (Transaction, Payment, Report-style namespaces). The tests folder is often more illustrative than the README for request/response shapes.

Implementation Patterns

Wrap the SDK in an app-level service. Don't scatter new Client(...) or raw calls through controllers. A thin PaymentService that takes the singleton and exposes register(), verify(), refund() keeps the SDK swappable and gives you one place to add logging and error translation.

Register-then-redirect flow. Always commit the order to the database before calling the gateway. Store the SDK's returned token and the session ID alongside the order. If registration fails, the order exists in pending rather than not at all.

$order = Order::create([...]);

$response = $this->p24->transaction()->register([
    'sessionId'  => (string) $order->id,      // must be unique per P24 session
    'amount'     => $order->total_grosze,    // integer, smallest currency unit
    'currency'   => 'PLN',
    'description' => "Order #{$order->id}",
    'email'      => $user->email,
    'country'    => 'PL',
    'language'   => 'pl',
    'urlReturn'  => route('checkout.return'),
    'urlStatus'  => route('webhooks.p24'),
    'timeLimit'  => 15,
]);

$order->update(['p24_token' => $response->token]);
return redirect($response->redirectUrl);

Webhook handler = verify + confirm. The urlStatus callback is unauthenticated HTTP from P24. Recompute the sign with your CRC, call the SDK's verify() to confirm the amount/currency/session against the gateway (don't trust the payload), then mark the order paid. This "confirmation" step is mandatory in P24's model — skipping it leaves transactions unsettled even though the user was charged.

Use a queued job for the confirmation call, keyed on sessionId with a uniqueness lock, so retries and duplicate callbacks don't double-credit an order.

Idempotent notification endpoint. Return 200 quickly, do the work in a job. P24 retries callbacks for a while.

Testing. Bind a fake Client in tests (or a fake PaymentService) so no HTTP leaves the container. For an end-to-end sandbox check, the P24 test-card numbers and the sandbox urlReturn (must be reachable — use a tunnel like Expose/ngrok) are your only true integration test.

Gotchas and Tips

  • This is not a Laravel-first package. No facade, no config/przelewy24.php out of the box, no php artisan vendor:publish. You own the wiring — do it once in a provider and forget it.
  • Money is in grosze. Passing 19.99 instead of 1999 is the single most common bug. Cast to int at the boundary; never let floats reach the SDK.
  • sessionId must be unique across your merchant account. If you reuse order IDs after a failed attempt, P24 will reject with a duplicate-session error. Prefix with a nonce or use a UUID per attempt.
  • CRC vs apiKey are different things. CRC signs the outgoing transaction payload and the incoming webhook; apiKey authenticates the REST confirmation call. Mixing them up yields 401s on verify and silent signature failures on register.
  • Amount mismatch on verify is fatal. The gateway returns the registered amount; if your stored total drifted (discounts, tax recalcs, currency rounding), verify() fails and the payment sits unsettled. Snapshot the total at registration and never recompute.
  • Sandbox flag is a constructor boolean. Forget to flip P24_SANDBOX=false in production and every request goes to the test environment — orders will "succeed" and charge nothing. Gate this with a runtime check (fail boot if app()->isProduction() && config('...sandbox')).
  • urlReturn and urlStatus must be absolute URLs reachable from P24's servers. localhost works only for urlReturn (browser redirect), never for urlStatus.
  • Error handling: SDK throws typed exceptions for request/response problems; wrap calls and translate to your own PaymentException so controllers stay clean and logs carry the P24 error code/message — those messages are the fastest debugging path.
  • Response object property names don't always match request names (redirectUrl vs url, token vs sessionId). Print $response once in tinker in the sandbox before trusting autocompletion — the SDK is loosely typed and IDE hints will lie.
  • Refunds and reports are read-only or state-change operations with their own auth (reportKey for reports). They're handy for nightly reconciliation jobs: pull the day's settlements into a p24_settlements table and diff against orders to catch drift.
  • No DI in the SDK: every call reaches for config at construction. If you ever need multi-merchant support (e.g. per-brand), don't use the singleton binding — resolve a scoped client from a factory keyed by merchant.
  • Version pinning matters: it's a small, MIT, single-maintainer package. Pin a minor version in composer.json and read the changelog before upgrading — enum/response shape changes have shipped without major bumps historically.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console