Integrate Yappy and Panama payments without surprises (Laravel + WordPress)

Integrate Yappy and Panama payments without surprises (Laravel + WordPress)

Updated: 15 min read
  • Yappy
  • Payments
  • Laravel
  • WordPress
  • Panama
  • BAC
  • Paguelo Fácil

Adding a “Pay with Yappy” button is the visible part. What prevents headaches is the invisible part: the amount is calculated on the server, the order has clear states, and the system knows what to do if the customer closes the app mid-payment.

This guide describes a backend-first pattern with Laravel. If your storefront is WordPress or WooCommerce, the CMS stays as the shopfront; sensitive logic lives outside the theme. The same approach works for Yappy (Banco General), BAC Credomatic, Paguelo Fácil, and unified gateways.

Why it matters in Panama

Yappy is a widely used payment method. A poorly designed flow does not just “fail in staging”: it creates ghost sales, charges without orders, or paid orders nobody can prove to support or accounting.

  • Trust: the customer needs to know whether they paid, without ambiguity.
  • Operations: the team must reconcile bank vs orders without endless spreadsheets.
  • Security: if the browser decides the price, someone will manipulate it.
  • Scalability: tomorrow you may want BAC or Paguelo Fácil without rewriting the store.

What Yappy looks like in practice

Think of Yappy as a digital teller window: your server requests a charge intent, the customer completes payment in the app or redirect, and your system receives confirmation through a trusted channel (not only the return URL).

  1. Merchant onboarding and credentials (merchantId / secret) in the commercial portal.
  2. The server generates a payment URL or intent with the correct amount.
  3. The user completes payment in the Yappy flow (app / redirect).
  4. Redirect + endpoint notification update the order after signature validation.

Golden rule: payment starts in the backend

Before showing the button, the server must do the heavy lifting:

  1. Create or retrieve the order with items, currency, and taxes.
  2. Calculate the total on the server (never trust the browser JSON).
  3. Save a payment record in pending state with an internal order_id.
  4. Request the payment URL / token from Yappy with those figures.
  5. Return to the front end only what is needed to continue (redirect or minimal data).

WordPress / WooCommerce without polluting the theme

On sites with Elementor, custom themes, or WooCommerce, secrets must not live in functions.php or page-builder snippets. That is like taping the safe key to the shop window.

  • 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 (steps)

  1. Order + Payment models with normalized states.
  2. PaymentGateway service with adapters behind an interface.
  3. Protected endpoint to start payment: validates cart, calculates total, persists pending.
  4. Callback/IPN endpoint: verifies signature, is idempotent, dispatches reconciliation job.
  5. Return page that queries DB state; does not mark paid from the query string.
  6. Queue for retries when the bank notifies late.
  7. Secrets only in host env (Coolify: service variables, not .env in Git).

Normalized states

Internal stateMeaning
pendingIntent created; no reliable confirmation yet
paidCharge confirmed by callback / signature validation
rejectedRejected by the provider
cancelledUser aborted
expiredOperational timeout

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 with no visible callback.
  • Deploying with the latest tag and secrets baked into the Docker image.
  • Not persisting the provider payload: impossible to audit later.

Technical checklist

  1. Credentials only in environment variables.
  2. Sandbox and production separated.
  3. Idempotency: the same order_id does not create two charges.
  4. Persist payload for auditing.
  5. Validate what the provider sends back (signature / fields).
  6. Jobs for reconciliation retries.
  7. Logs without secrets or card data.
  8. Result page that queries the backend.
  9. Healthcheck and workers alive on deploy.
  10. Runbook for secret rotation and IPN reprocessing.

This integration connects with Docker, CI/CD, and Coolify, security auditing, and online payments .

Frequently asked questions

Can Yappy be integrated on the frontend only?

No. The button or redirect can live on the frontend, but the amount, order, and signature must be generated on the backend. If the browser decides the price, someone will manipulate it.

Does it work for WordPress and WooCommerce?

Yes. Connect checkout to a Laravel API (or backend module) that talks to Yappy, BAC, or Paguelo Fácil, instead of putting secrets inside the theme.

What if the user closes the app mid-payment?

That is why you persist states (pending, paid, rejected, cancelled, expired) and process the callback/IPN. Do not confirm an order just because the user returned to a success URL.

Can Yappy be unified with BAC and Paguelo Fácil?

Yes: an internal contract in Laravel and one adapter per provider. The store is not rewritten every time a bank changes.

How long does a clean integration take?

A well-built single charge (sandbox, callback, basic reconciliation) usually takes days, not months. Subscriptions or multi-provider setups expand scope and must be defined in writing before coding.