Integrating Yappy in a Panamanian merchant involves more than adding a payment button. You need a clear flow, server-signed amounts, states that survive user interruptions, and a backend that can explain why an order was paid or not.
This article describes the backend-first pattern with Laravel and, when the front end is WordPress or WooCommerce, keeps the CMS as the storefront and checkout UI while moving sensitive logic out of the theme. It applies to integrations with Yappy, BAC Credomatic, Paguelo Fácil, and unified gateways.
What Yappy looks like in practice
Yappy (Banco General) is a widely used payment method in Panama. In typical commercial integrations:
- Merchant onboarding and credentials (
merchantId/ secret) in the commercial portal. - Generation of a payment URL or payment intent from the server.
- The user completes payment in the Yappy flow (app / redirect).
- The system receives the result via redirect + endpoint notification and updates the order.
Golden rule: payment starts in the backend
Before showing the button on the front end, the server must:
- Create or retrieve the order with items, currency, and taxes.
- Calculate the total on the server (never trust the browser JSON).
- Save a payment record in
pendingstate with an internalorder_id. - Request the payment URL / token from Yappy with those figures.
- Redirect or return to the front end only what is needed to continue.
WordPress / WooCommerce without polluting the theme
On WordPress sites with Elementor, custom themes, or WooCommerce, secrets must not live in functions.php or page builder snippets.
Recommended pattern:
- WooCommerce creates the local order.
- A thin endpoint or plugin calls the Laravel API (gateway).
- Laravel talks to Yappy / BAC / Paguelo Fácil.
- WordPress reflects the state when the backend confirms.
Laravel implementation
Order+Paymentmodels with normalized states.PaymentGatewayservice with adapters behind an interface.- Protected endpoint to start payment: validates cart, calculates total, persists
pending. - Callback/IPN endpoint: verifies signature, is idempotent, dispatches reconciliation job.
- Return page that queries DB state; does not mark
paidfrom query string. - Queue for retries when the bank notifies late.
- Secrets only in host env (Coolify: service variables, not
.envin Git).
Normalized states
| Internal state | Meaning |
|---|---|
pending | Intent created; no reliable confirmation yet |
paid | Charge confirmed by callback/signature validation |
rejected | Rejected by the provider |
cancelled | User aborted |
expired | Operational timeout |
Technical checklist
- Credentials only in environment variables.
- Sandbox vs production separated.
- Idempotency: the same
order_iddoes not create two charges. - Persist payload for auditing.
- Validate what the provider sends back.
- Jobs for reconciliation retries.
- Logs without secrets or card data.
- Result page that queries the backend.
- Healthcheck and workers alive on deploy.
- Runbook for secret rotation and IPN reprocessing.
Common production mistakes
- Confirming a sale only because the user reached
/pago-exitoso. - Leaving the secret in a WordPress plugin versioned in Git.
- Mixing Yappy, BAC, and Paguelo Fácil logic in one giant
if. - Forgetting the "user paid and closed the app" case without a callback.
- Deploying with
latestand secrets baked into the Docker image.
This integration connects with Docker, CI/CD, and Coolify, security auditing, and online payments .