Przelewy24 payments with Sources Beta

Use Sources to accept payments using Przelewy24, the most popular payment method in Poland.

Stripe users in Europe and the United States can accept Przelewy24 payments from customers in Poland using Sources.

During the payment process, a Source object is created and your customer is redirected to their bank’s website or mobile application to authorize the payment. After completing this, your integration uses the source to make a charge request and complete the payment.

Przelewy24 is a push-based, single-use and synchronous method of payment. This means your customer takes action to send the amount to you through a redirect and there is immediate confirmation about the success or failure of a payment.

Step 1: Create a Source object

A Source object is either created client-side using Stripe.js or server-side using the Source creation endpoint, with the following parameters:

Parameter Value
type p24
amount A positive integer in the smallest currency unit representing the amount to charge the customer (e.g., 1099 for a €10.99 payment).
currency eur or pln (Przelewy24 payments must be in either Euros or Polish Zloty).
The name of the account holder.
owner[email] The email address of the account holder.
redirect[return_url] The URL the customer should be redirected to after the authorization process.
A custom statement descriptor for the payment.

To create a source with Stripe.js, first include the library within your website and set your publishable API key. Once included, use the following createSource method to create a source client-side:

stripe.createSource({ type: 'p24', amount: 1099, currency: 'eur', owner: { name: 'Jenny Rosen', email: '', }, redirect: { return_url: '', }, }).then(function(result) { // handle result.error or result.source });

Using either method, Stripe returns a Source object containing the relevant details for the method of payment used. Information specific to Przelewy24 is provided within the p24 subhash.

{ "id": "src_16xhynE8WzK49JbAs9M21jaR", "object": "source", "amount": 1099, "client_secret": "src_client_secret_UfwvW2WHpZ0s3QEn9g5x7waU", "created": 1445277809, "currency": "eur", "flow": "redirect", "livemode": true, "owner": {
See all 32 lines "address": null, "email": "", "name": "Jenny Rosen", "phone": null, "verified_address": null, "verified_email": "", "verified_name": "Jenny Rosen", "verified_phone": null }, "redirect": { "return_url": "", "status": "pending", "url": "" }, "statement_descriptor": null, "status": "pending", "type": "p24", "usage": "single_use", "p24": { "reference": "P24-000-111-222" } }

Source creation in mobile applications

If you’re building an iOS or Android app, you can implement sources using our mobile SDKs. Refer to our sources documentation for iOS or Android to learn more.

Statement descriptors with Przelewy24

Przelewy24 lets you provide a custom statement descriptor before the customer is redirected to authenticate the payment. It can be specified by providing statement_descriptor when creating a source.

Additionally, when the customer approves the payment, a unique reference will be stored on the Source under p24[reference]. You can share this reference with your customer to help locate payments.

Providing a custom statement descriptor within a subsequent charge request has no effect.

Error codes

Source creation for Przelewy24 payments may return any of the following errors:

Error Description
payment_method_not_available The payment method is currently not available. You should invite your customer to fallback to another payment method to proceed.
processing_error An unexpected error occurred preventing us from creating the source. The source creation should be retried.
invalid_owner_email The owner email address is invalid. It must be a valid email address.
invalid_currency The currency is not supported for Przelewy24. It must either be 'eur' or 'pln'.

Step 2: Have the customer authorize the payment

When creating a source, its status is initially set to pending and cannot yet be used to make a charge request. Your customer must authorize a Przelewy24 payment to make the source chargeable. To allow your customer to authorize the payment, redirect them to the URL provided within theredirect[url] attribute of the Source object.

After the authorization process, your customer is redirected back to the URL provided as a value of redirect[return_url]. This happens regardless of whether authorization was successful or not. If the customer has authorized the payment, the Source object’s status is updated to chargeable and it is ready to use in a charge request. If your customer declines the payment, the status transitions to failed.

Stripe populates the redirect[return_url] with the following GET parameters when returning your customer to your website:

  • source: a string representing the original ID of the Source object
  • livemode: indicates if this is a live payment, either true or false
  • client_secret: used to confirm that the returning customer is the same one who triggered the creation of the source (source IDs are not considered secret)

You may include any other GET parameters you may need when specifying redirect[return_url]. Do not use the above as parameter names yourself as these would be overridden with the values we populate.

Mobile applications

To integrate Przelewy24 within a mobile application, provide your application URI scheme as the redirect[return_url] value. By doing so, your customers are returned to your app after completing authorization. Refer to our Sources documentation for iOS or Android to learn more.

If you are integrating without using our mobile SDKs, the redirect URL must be opened using the device’s native browser. The use of in-app web views and containers can prevent your customer from completing authentication—resulting in a lower conversion rate.

Testing the redirect process

When creating a Source object using your test API keys, you can follow the URL returned in the redirect[url] field. This leads to a Stripe page that displays information about the API request, and where you can either authorize or cancel the payment. Authorizing the payment redirects you to the URL specified in redirect[return_url].

Alternatively, to accelerate testing, use the following value for owner[email], where xxx_ is any prefix of your choice (these patterns are significant only in testmode):

Email Address Effect The source will be created as pending, but automatically transition to chargeable within seconds of its creation.

Step 3: Charge the Source

Once the customer has authenticated the payment, the source’s status transitions to chargeable and it can be used to make a charge request. This transition happens asynchronously and may occur after the customer was redirected back to your website.

Some customers using Przelewy24 assume that the order process is complete once they have authenticated the payment and received confirmation from their bank. This results in customers who close their browser instead of following the redirect and returning to your app or website.

For these reasons it is essential that your integration rely on webhooks to determine when the source becomes chargeable in order to create a charge. Please refer to our best practices for more details on how to best integrate payment methods using webhooks.


The following webhook events are sent to notify you about changes to the source’s status:

Event Description
source.chargeable A Source object becomes chargeable after a customer has authenticated and verified a payment.
source.failed A Source object failed to become chargeable as your customer declined to authenticate the payment.
source.canceled A Source object expired and cannot be used to create a charge.

Make a charge request using the source

Once the source is chargeable, from your source.chargeable webhook handler, you can make a charge request using the source ID as the value for the source parameter to complete the payment.

curl \ -u sk_test_4eC39HqLyjWDarjtT1zdp7dc: \ -d amount=1099 \ -d currency=eur \ -d source=src_18eYalAHEMiOZZp1l9ZTjSU0
# Set your secret key. Remember to switch to your live secret key in production! # See your keys here: Stripe.api_key = 'sk_test_4eC39HqLyjWDarjtT1zdp7dc' charge = Stripe::Charge.create({ amount: 1099, currency: 'eur', source: 'src_18eYalAHEMiOZZp1l9ZTjSU0', })
# Set your secret key. Remember to switch to your live secret key in production! # See your keys here: stripe.api_key = 'sk_test_4eC39HqLyjWDarjtT1zdp7dc' charge = stripe.Charge.create( amount=1099, currency='eur', source='src_18eYalAHEMiOZZp1l9ZTjSU0', )
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: \Stripe\Stripe::setApiKey('sk_test_4eC39HqLyjWDarjtT1zdp7dc'); $charge = \Stripe\Charge::create([ 'amount' => 1099, 'currency' => 'eur', 'source' => 'src_18eYalAHEMiOZZp1l9ZTjSU0', ]);
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: Stripe.apiKey = "sk_test_4eC39HqLyjWDarjtT1zdp7dc"; ChargeCreateParams params = ChargeCreateParams.builder() .setAmount(1099L) .setCurrency("eur") .setDescription("Example charge") .setStatementDescriptor("Custom descriptor") .setSource("src_18eYalAHEMiOZZp1l9ZTjSU0") .build(); Charge charge = Charge.create(params);
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: const stripe = require('stripe')('sk_test_4eC39HqLyjWDarjtT1zdp7dc'); const charge = await stripe.charges.create({ amount: 1099, currency: 'eur', source: 'src_18eYalAHEMiOZZp1l9ZTjSU0', });
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: stripe.Key = "sk_test_4eC39HqLyjWDarjtT1zdp7dc" chargeParams := &stripe.ChargeParams{ Amount: stripe.Int64(1099), Currency: stripe.String(string(stripe.CurrencyEUR)), } chargeParams.SetSource("src_18eYalAHEMiOZZp1l9ZTjSU0") ch, err := charge.New(chargeParams)
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: StripeConfiguration.ApiKey = "sk_test_4eC39HqLyjWDarjtT1zdp7dc"; var options = new ChargeCreateOptions { Amount = 1099, Currency = "eur", Source = "src_18eYalAHEMiOZZp1l9ZTjSU0", }; var service = new ChargeService(); Charge charge = service.Create(options);

Przelewy24 Sources are single-use and cannot be used for recurring or additional payments. Refer to our Sources & Customers guide for more information on how single-use Sources interact with Customers.

Step 4: Confirm that the charge has succeeded

Since Przelewy24 is a synchronous payment method and the customer has already authenticated the payment as part of the redirect, unless there is an unexpected error, the Charge will immediately succeed.

Event Description
charge.succeeded The charge succeeded and the payment is complete.

We recommend that you rely on the charge.succeeded webhook event to notify your customer that the payment process has been completed and their order is confirmed. Please refer to our best practices for more details on how to best integrate payment methods using webhooks.

Disputed payments

The risk of fraud or unrecognized payments is extremely low with Przelewy24 as the customer must authenticate the payment with their bank. As such, there is no dispute process that can result in a chargeback and funds withdrawn from your Stripe account.


Payments made with Przelewy24 can only be submitted for refund within 180 days from the date of the original charge. After 180 days, it is no longer possible to refund the charge.

Sources expiration

A chargeable Przelewy24 source must be charged within six hours of becoming chargeable. If it is not, its status is automatically transitioned to canceled and your integration receives a source.canceled webhook event. Once a chargeable source is canceled, the customer’s authenticated Przelewy24 payment is refunded automatically—no money is moved into your account. For this reason, make sure the order is canceled on your end and the customer is notified when you receive the source.canceled event.

Additionally, pending sources are canceled after one hour if they are not used to authenticate a payment, ensuring that all sources eventually transition out of their pending state to the canceled state if they are not used.

Related resources