BLIK
BLIK is a Polish mobile payment method. The customer generates a 6-digit code in their banking app, enters it at checkout, and approves the payment in the same app.
BLIK is available for payments in Polish złoty (PLN).
How it works
- Customer: generates a 6-digit BLIK code in their banking app.
- Checkout or your frontend: collects the code.
- Your backend or Checkout: confirms the payment with the code.
- Paypercut: returns the Payment Intent with
status=requires_actionandnext_action.type=blik_authorize. The payment is pending. - Customer: approves the payment in their banking app.
- Paypercut: updates the Payment Intent to its final result and sends payment webhooks.
A BLIK code can be used once and expires after a short time (about two minutes). If the customer doesn't approve the payment in time, the payment fails and the customer needs a new code.
Before you begin
- BLIK must be enabled for your account. The account capability
blik_paymentsmust beactive. Contact Paypercut to enable it. - The payment currency must be
PLN. - Your integration must handle the pending state. A confirmed BLIK payment is not successful until the customer approves it.
Accept BLIK payments
Choose one of the following integrations.
Create a Checkout Session in PLN and include blik in payment_method_types. Checkout shows a BLIK option, collects the code, and shows the customer when to approve the payment in their banking app.
{
"amount": 4999,
"currency": "PLN",
"payment_method_types": ["blik"],
"success_url": "https://yourdomain.com/checkout/success",
"cancel_url": "https://yourdomain.com/checkout/cancel",
"line_items": [
{ "name": "Product", "amount": 4999, "quantity": 1 }
]
}
- Hosted Checkout: redirect the customer to the Checkout URL.
- Embedded Checkout: render the Checkout on your page with
@paypercut/checkout-js. The customer enters the BLIK code without leaving your site.
See Checkouts for the full Checkout Session setup.
Use the direct API when you collect the BLIK code in your own payment form.
- Your frontend: collect the 6-digit code and send it to your backend.
- Your backend: create and confirm a Payment Intent with the code. Use your secret key and send an
Idempotency-Key.
curl https://api.paypercut.io/v1/payment_intents \
-X POST \
-H "Authorization: Bearer $PAYPERCUT_SECRET_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: order-1001-blik" \
-d '{
"amount": 4999,
"currency": "PLN",
"payment_method_data": { "type": "blik" },
"payment_method_options": {
"type": "blik",
"blik": { "code": "999000" }
},
"confirm": true
}'
- Your frontend: when the response has
status=requires_actionandnext_action.type=blik_authorize, tell the customer to approve the payment in their banking app. - Your backend: wait for the final result. Listen for the
payment.succeededandpayment.failedwebhooks, or retrieve the Payment Intent (GET /v1/payment_intents/{id}) every few seconds until itsstatusis no longerrequires_action.
Do not treat the payment as successful when the confirmation request returns. Only the final Payment Intent status or the payment webhook confirms the result.
:::
Test the integration
Use your test mode API keys. In test mode, the BLIK code decides the result.
| BLIK code | Scenario | Result |
|---|---|---|
999000 |
Customer approves the payment | Payment succeeds |
934111 |
Customer declines the payment in the banking app | Payment fails with decline_code=customer_declined |
949111 |
Customer doesn't approve the payment in time | Payment fails with decline_code=customer_timeout |
960111 |
Insufficient funds | Payment fails with decline_code=insufficient_funds |
990111 |
BLIK transaction limit exceeded | Payment fails with decline_code=payment_limit_exceeded |
989111 |
Timeout at the customer's bank | Payment fails with decline_code=temporarily_unavailable |
902111 |
Bank declines the payment | Payment fails with decline_code=generic_decline |
912111 |
Bank declines the payment for security reasons | Payment fails with decline_code=generic_decline |
927111 |
Payment declined | Payment fails with decline_code=generic_decline |
969111 |
Payment declined for security reasons | Payment fails with decline_code=generic_decline |
956111 |
System error | Payment fails with decline_code=generic_decline |
961111 |
General error | Payment fails with decline_code=generic_decline |
A result can arrive in the confirmation response or later, after the pending state. Handle both, as in live mode.
Handle errors
When a BLIK payment fails, the Payment Intent includes last_payment_error with a decline_code, an advice_code, and a message you can show to the customer.
decline_code |
What happened | What the customer can do |
|---|---|---|
customer_declined |
The customer declined the payment in their banking app | Pay again with a new code or another payment method |
customer_timeout |
The customer didn't approve the payment in time | Generate a new code and try again |
invalid_one_time_code |
The code was wrong or no longer active | Generate a new code and try again |
one_time_code_already_used |
The code was already used | Generate a new code and try again |
one_time_code_expired |
The code expired before it was used | Generate a new code and try again |
insufficient_funds |
The bank account doesn't have enough funds | Add funds or use another payment method |
payment_limit_exceeded |
The payment exceeds a limit on the bank account | Change the limit in the banking app or use another payment method |
temporarily_unavailable |
BLIK or the bank didn't respond in time | Try again later |
generic_decline |
The payment was declined without a specific reason | Try again or use another payment method |
Each new attempt needs a new BLIK code.
Go live
- Make sure BLIK is enabled for your live account (
blik_paymentsisactive). - Switch to your live API keys.
- Confirm that your integration handles the pending state, the final result, and each failure in Handle errors.

