Blog
ENPL

Stripe + BLIK + Przelewy24 for small businesses — what took me 6h saves you a week

Online payments setup for an agritourism, honey shop, course — from account to first webhook. Concrete walls that hit you (BLIK on Stripe, VAT invoices, data retention), with doc links.

·6 min read
Stripe + BLIK + Przelewy24 for small businesses — what took me 6h saves you a week

Over the last six months I got the same question 5 times: "I want to accept BLIK on my site, how do I tackle this". Client runs an agritourism / apiary / yoga course and only knows Stripe is American, Przelewy24 is Polish, and BLIK should be everywhere. Here's the breakdown of what I actually picked for the last 4 clients and why.

Three questions before you pick a provider

  1. Selling in PLN or EUR/USD? If mostly PL, Przelewy24 or Stripe-with-BLIK. If EU mix, Stripe wins.
  2. Issue invoices yourself or want the system to do it? Stripe doesn't issue PL-compliant invoices, Przelewy24 and Tpay do.
  3. How many transactions monthly? < 50/mo, manual BLIK link works. > 50, automation + webhook + DB.

Stripe — when to pick it

Plus:

  • Best DX (developer experience): docs from another planet, SDK for everything
  • Webhooks work like electricity, reliable, retries, signature verification
  • Dashboard in English but logical, PDF reports
  • Subscriptions, refunds, dispute management, everything out-of-the-box
  • BLIK officially supported as payment method since September 2024

Minus:

  • PL-compliant invoices don't exist, Stripe issues a receipt, not an invoice. You need integration with fakturownia/iFirma/wFirma or Resend + template.
  • 2.9% + 0.30 EUR / transaction, pricier than Polish gateways for small transactions
  • Payouts to PL account every 7 days (default), can be shortened to 2 days

Setup BLIK on Stripe:

// app/api/checkout/route.ts
import Stripe from "stripe";
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);
 
export async function POST(req: Request) {
  const { items } = await req.json();
  const session = await stripe.checkout.sessions.create({
    mode: "payment",
    payment_method_types: ["card", "blik", "p24"], // BLIK + Przelewy24 + cards
    currency: "pln",
    line_items: items.map((i) => ({
      price_data: {
        currency: "pln",
        product_data: { name: i.name },
        unit_amount: i.priceCents,
      },
      quantity: i.qty,
    })),
    success_url: `${process.env.SITE_URL}/thanks?session={CHECKOUT_SESSION_ID}`,
    cancel_url: `${process.env.SITE_URL}/cart`,
  });
  return Response.json({ url: session.url });
}

That's it. Stripe Checkout shows a BLIK code in PLN to enter, P24 redirect to bank, Visa/Mastercard. Mobile-first.

Przelewy24 (P24) — when

Plus:

  • VAT invoices generated automatically on the P24 side
  • Rates 1.4-1.9% (vs 2.9% Stripe)
  • Polish support (phone, email in Polish)
  • BLIK natively, Apple/Google Pay, all Polish banks via pay-by-link

Minus:

  • DX worse than Stripe (REST API, docs 50% in Polish, 50% PL/EN mix)
  • Webhooks work, but signature verification less intuitive
  • Subscriptions need a separate module

Webhook setup in Next.js:

// app/api/p24/webhook/route.ts
import { createHmac } from "crypto";
 
export async function POST(req: Request) {
  const body = await req.text();
  const sign = req.headers.get("x-p24-signature");
 
  // P24 signs sha384 of (sessionId|orderId|amount|currency|crc)
  const expected = createHmac("sha384", process.env.P24_CRC!)
    .update(body)
    .digest("hex");
 
  if (sign !== expected) return new Response("invalid sig", { status: 401 });
 
  const data = JSON.parse(body);
  if (data.statusCode === 1) {
    // payment confirmed → mark order paid in DB
    await markPaid(data.orderId);
  }
  return new Response("ok");
}

P24 has a free sandbox, you can test end-to-end without real money.

What I picked for the last 4 clients

ClientPickWhy
Apiary (e-commerce honey)P24Auto VAT invoices, client didn't want fakturownia integration
Demo agritourismStripe + BLIKClient also targets EU tourists, EUR needed
Wedding venue (deposits)StripeSubscriptions (deposit + final payment), Stripe handles this elegantly
Cosmetology clinicP24 + manual BLIK linkLow transaction volume, simpler setup

Traps that actually hit you

1. "BLIK on Stripe requires a PL business entity." True until October 2024, needed a Polish tax ID. Since end of 2024 that's no longer required (international Stripe accepts BLIK), but many devs have stale info. Check stripe.com/docs/payments/blik.

2. "VAT invoices with Polish buyer data." Stripe doesn't collect buyer's tax ID by default. You need a custom field in Checkout or your own form before redirect. P24 has it built in.

3. "GDPR and payment data." Don't store full card numbers (Stripe and P24 never send them in webhooks, but I sometimes see programmers logging request body without masking). Keep only last4 and brand.

4. "Refunds and tax." Refund in Stripe = -X PLN in cash. But if you already issued a VAT invoice, you have to issue a correction. If you use fakturownia with auto-sync to Stripe webhooks, most of this happens for you.

5. "Stripe customs declaration." Stripe payout → your PL account = intra-EU transfer (Stripe Payments Europe SAS, Ireland). No customs declarations. But in your tax return, Stripe payouts are income, log them on the fly.

Real-world costs (4 clients, 6 months)

Average costs per client over 6 months:

Apiary (P24):      43 transactions/mo × 89 PLN avg = 3,827 PLN turnover
                   × 1.6% = 61 PLN/mo fees
                   = 1.6% effective
 
Wedding venue (Stripe): 8 deposits/mo × 1500 PLN = 12,000 PLN
                        × 2.9% + 8×1.20 EUR = ~365 PLN/mo
                        = 3.0% effective (pricier, but subscription value worth it)

P24 has ~2x lower fees on small transactions. Stripe cheaper when transaction > 500 PLN (because flat 1.20 EUR amortizes).

30-second decision tree

  • Selling physical products / services in PLN, avg transaction < 200 PLN, > 30/mo: P24
  • Selling subscriptions, courses, currency mix: Stripe
  • Selling occasionally (< 10/mo), client asks for BLIK: manual BLIK link generated from banking + traditional transfer in footer. No gateway.
  • Targeting EU / global: Stripe, but integrate fakturownia
  • Small businesses with strong PL brand (locality matters): P24 (client sees "Przelewy24" at checkout and trusts)

What else is worth knowing

  • Tpay exists, but I park it, DX worse than P24, prices comparable, smaller market share.
  • Autopay (Blue Media), used in public transit and parking, for normal e-commerce loses to P24.
  • Revolut Business has a checkout link generator, but no BLIK, I don't treat it as a Stripe/P24 alternative.
  • PayU, works, Polish, but DX from 2010. Only if you already have PayU for other projects and don't want to migrate.

Setup of the whole thing is simpler than it looks. For a single client it's ~6h of dev time (Stripe full integration with fakturownia) or ~2h (P24 basic). For myself I built a reusable module I drop into every new e-commerce.

If you want to roll this out for your business, drop a line. I also audit existing setups (is anything broken, are invoices being issued, are webhooks landing).