Card payments and other gateways
Out of the box the shop takes bank transfer, cash on delivery, Bizum and crypto. That works without registering with anyone, and without anyone being able to close your account.
If you also want cards, five gateways are ready. Each one appears by itself as soon as you supply its credentials; without them, it does not exist.
Which to choose
Section titled “Which to choose”| Best for | Brings | |
|---|---|---|
| MONEI | Spain | Bizum, cards, PayPal, Apple and Google Pay |
| Stripe | International | Cards, Apple and Google Pay, SEPA, iDEAL |
| PayPal | The button buyers ask for most | PayPal and cards |
| Mollie | Northern Europe | iDEAL, Bancontact, cards, SEPA |
| Adyen | High volume | Cards and local methods across half the world |
If you sell in Spain, MONEI. It is a Payment Institution licensed by the Bank of Spain, reaches the same banking rails as your bank’s card terminal, and does real Bizum.
What about Redsys? It is the terminal behind CaixaBank, BBVA and Santander, and it would be the first choice, but its official libraries are PHP, Java and .NET. Integrating it here would mean writing its cryptographic signature by hand, and in a payment that is the class of bug no test finds: the customer who got charged twice finds it. MONEI covers that ground without anybody inventing crypto.
Turning one on
Section titled “Turning one on”Put the variables in the backend’s .env and restart. That is all.
# Spain: Bizum and cardsMONEI_API_KEY=pk_...MONEI_WEBHOOK_URL=https://your-shop.com/hooks/payment/pasarela_monei
# InternationalSTRIPE_API_KEY=sk_live_...STRIPE_WEBHOOK_SECRET=whsec_...
# PayPalPAYPAL_CLIENT_ID=...PAYPAL_CLIENT_SECRET=...PAYPAL_WEBHOOK_ID=... # optional, see below
# The storefront's domain: buyers come back here after paying elsewherePAYMENT_RETURN_URL=https://your-shop.comAnd in the storefront’s .env, if you use Stripe:
STRIPE_PUBLIC_KEY=pk_live_... # the public one, the browser sees itSITE_URL=https://your-shop.comThe exact return path is set by the theme, because it changes with the page’s
language: a buyer who was on /en/checkout comes back to /en/checkout/volver
and does not land in Spanish right as they confirm the purchase.
Then you have to enable it at checkout: Panel → Settings → Regions, and tick it in the region it belongs to. Being configured is not being visible.
If you sell CBD or hemp
Section titled “If you sell CBD or hemp”Stripe forbids it in its UK and EU terms, and so does Shopify Payments. It is not a technical problem and no amount of configuration fixes it: the account gets closed, usually without warning and with the money held.
Specialist processors charge 1 % to 5 % and hold reserves of up to 10 % for 180 days.
That is why the built-in methods — transfer, cash on delivery, Bizum and crypto — are not a stopgap until cards arrive. For that sector they are the reliable route, and for anyone they are what stops you depending on nobody objecting to what you sell.
How paying works, per gateway
Section titled “How paying works, per gateway”| What the buyer sees | |
|---|---|
| Transfer, cash on delivery, Bizum | Confirms the order and that is it |
| PayPal, Mollie, MONEI | Goes to the gateway’s page and comes back |
| Stripe | Pays without leaving the shop, in a Stripe form |
| Adyen | Pays without leaving, in Adyen’s Drop-in with all its methods |
With the last two the order is closed on return, not when the button is pressed. Closing it earlier would mean accepting orders nobody has paid for.
And the return page does not believe the URL. The buyer coming back only
means “you may look now”: the gateway is asked, and if the money is not there,
there is no order — however much it says ?success=true, which is something
anyone can type.
Adyen depends on its webhook
Section titled “Adyen depends on its webhook”With the others, on return you ask the gateway and you are done. With Adyen you cannot: its API cannot answer about a session without a value only the browser holds, and its own documentation says the result arrives asynchronously, in a webhook.
That webhook is HMAC-signed, so what it says can be trusted, and it carries the status and the amount. But it means one important thing:
With Adyen, the webhook has to arrive. If its URL is not reachable from the internet, the buyer pays and the order never closes. It does not work locally without a tunnel.
The Drop-in shows every method enabled on your account at once — cards, iDEAL, Klarna, whatever — and handles 3-D Secure itself.
Charging on dispatch, not on purchase
Section titled “Charging on dispatch, not on purchase”With soloAutorizar the gateway holds the money when the order is placed
and does not take it until you capture it from the panel, on dispatch.
It is for not charging for what you might not be able to ship. But a hold expires — from a few days to a month depending on the gateway — and once it does there is nothing to charge. If you are not going to prepare orders quickly, do not turn it on.
In the panel, a held payment shows as authorised, not paid. That is deliberate: shipping against a hold is giving the goods away if it expires.
The gateway’s notifications
Section titled “The gateway’s notifications”Every gateway notifies the shop when a payment changes. The URL is always:
https://your-shop.com/hooks/payment/pasarela_<gateway>What arrives in that notification is not believed. The signature is checked, only the payment’s identifier is taken from it, and the gateway is asked again what the status is. That sounds excessive until you think about what a webhook is: a request anyone who guesses the URL can send, saying “this one is paid”.
Per-gateway details:
- Stripe and Adyen sign with a secret. With no secret configured, the shop
accepts none of their notifications — an open route that marks orders as
paid cannot be left alive by an oversight in
.env. - MONEI signs with its own header; its SDK validates it.
- Mollie does not sign, on purpose: its notification carries only the identifier precisely so that you have to ask again.
- PayPal uses no shared secret: you ask PayPal whether the notification is
theirs.
PAYPAL_WEBHOOK_IDperforms that check; without it, the safety comes from re-reading the order.
If something fails
Section titled “If something fails”“falta el paquete stripe” — the gateway is configured but its library is
not installed. npm i stripe in the backend.
“La pasarela «adyen» necesita merchantAccount” — this appears at start-up, not at checkout, and that is deliberate: a misconfigured gateway has to show its face before there is a customer at the checkout.
A payment stays “pending” — look at the gateway’s notification log. Almost always it is the webhook URL, wrong or unreachable from outside.
Adding another gateway
Section titled “Adding another gateway”The five live in @pcreative/payments-contract, each on top of its gateway’s
official SDK. To add one more you implement six operations — create, read,
capture, cancel, refund and webhook — and register it like the rest. The rest of
the system never notices.