El mayor portal de MU Online de Brasil — desde 2003
Tutorial Avanzado Website

Cómo integrar donaciones con PayPal y PIX en el servidor de MU Online

Aprende a construir un sistema de donaciones completo para tu servidor de MU Online, integrando PayPal vía IPN/Webhook y PIX a través de pasarelas brasileñas, con acreditación automática de VIP y WCoin sin intervención manual.

GA Gabriel · Actualizado el 30 jun 2025 · ⏱ 14 de lectura
Respuesta rápida

Montar un sistema de donaciones confiable es uno de los pasos que más diferencia a un servidor de MU Online amateur de un proyecto sostenible. La mayoría de los administradores empiezan pidiendo comprobante por Discord y acreditando VIP a mano, lo que no escala, genera retrasos y abre espacio al err

Montar un sistema de donaciones confiable es uno de los pasos que más diferencia a un servidor de MU Online amateur de un proyecto sostenible. La mayoría de los administradores empiezan pidiendo comprobante por Discord y acreditando VIP a mano, lo que no escala, genera retrasos y abre espacio al error humano y a los estafadores. En este tutorial avanzado vas a construir un flujo de donación de punta a punta: una página de checkout en el sitio, integración con PayPal vía IPN/Webhook, integración con PIX a través de una pasarela brasileña (usando el estándar de cobro dinámico con QR Code y confirmación por webhook), y la acreditación automática de recompensas en la base de datos del juego. Todos los ejemplos de nombres de tablas, columnas y valores son solo ilustrativos y varían por versión (Season 6, Season 16, archivos IGCN, MuEMU, etc.) — verifica siempre el schema real de tu distribución antes de ejecutar cualquier SQL en producción.

El principio central que debes llevarte de esta guía es simple: nunca acredites una recompensa basándote en lo que el navegador del usuario te dice. La confirmación de pago válida viene siempre de una notificación servidor-a-servidor, firmada y verificable, enviada por el proveedor de pago directamente a tu backend. Todo lo demás es solo interfaz.

Requisitos previos

Antes de empezar, asegúrate de tener el entorno y los accesos de abajo. Sin ellos, el resto del tutorial no funciona.

  • Un sitio funcional en PHP 8.0 o superior (idealmente 8.2+) con acceso a composer para instalar SDKs.
  • Servidor web con HTTPS válido (Let's Encrypt ya lo resuelve). Los webhooks de PayPal y de las pasarelas PIX exigen un endpoint HTTPS público — nada de localhost ni certificado autofirmado.
  • Acceso a la base de datos del juego (SQL Server, en la mayoría de las distribuciones de MU) y a la base del sitio (MySQL/MariaDB, común en los CMS).
  • Una cuenta PayPal Business (la personal no emite las credenciales completas de la API REST).
  • Una cuenta en una pasarela de pago brasileña que ofrezca PIX vía API con webhook (Mercado Pago, Efí/antigua Gerencianet, Asaas, PagSeguro, entre otras). Los ejemplos usan el patrón genérico "crear cobro → recibir webhook".
  • Nociones de cola/cron o de transacciones SQL para garantizar una acreditación atómica.

> Seguridad: trata las credenciales de API (Client ID, Secret, tokens) como contraseñas. Nunca las pongas en el repositorio Git ni en JavaScript del front-end. Usa variables de entorno (.env) fuera de la raíz pública siempre que sea posible.

Arquitectura general del flujo

Antes de escribir código, visualiza el camino de una donación. El jugador nunca toca directamente la base del juego; pasa por capas que validan cada etapa.

  1. El jugador inicia sesión en el sitio y elige un paquete (ej.: R$ 20 = 5.000 WCoin + 30 días de VIP).
  2. El backend crea un pedido pendiente en la base del sitio, con un identificador único (order_id).
  3. El jugador es redirigido a PayPal o recibe un QR Code PIX.
  4. Tras pagar, el proveedor envía un webhook a tu servidor confirmando el pago.
  5. El backend valida la firma, verifica valor/moneda, marca el pedido como pagado y acredita la recompensa en la base del juego — todo de forma idempotente.
  6. El jugador ve el saldo actualizado en el panel.
CapaResponsabilidadNunca debe
Front-endMostrar paquetes e iniciar el pagoDecidir si algo fue pagado
Backend (pedidos)Crear/actualizar pedidos, generar cobroAcreditar sin webhook confirmado
Manejador de webhookValidar firma y confirmarConfiar en parámetros de retorno (?status=success)
Acreditación (game DB)Añadir VIP/WCoin de forma atómicaEjecutarse dos veces para la misma transacción

Modelado de la tabla de pedidos

Crea en la base del sitio una tabla para rastrear cada donación. La idempotencia depende de ella: la columna transaction_id del proveedor debe ser única para impedir el crédito duplicado.

CREATE TABLE donations (
    id            BIGINT AUTO_INCREMENT PRIMARY KEY,
    account       VARCHAR(20)  NOT NULL,          -- cuenta del juego
    method        ENUM('paypal','pix') NOT NULL,
    package_id    INT          NOT NULL,
    amount_brl    DECIMAL(10,2) NOT NULL,
    wcoin        INT          NOT NULL,
    vip_days      INT          NOT NULL DEFAULT 0,
    status        ENUM('pending','paid','credited','failed','refunded') DEFAULT 'pending',
    provider_txn  VARCHAR(120) NULL,
    ip            VARCHAR(45)  NULL,
    created_at    DATETIME     DEFAULT CURRENT_TIMESTAMP,
    paid_at       DATETIME     NULL,
    UNIQUE KEY uq_provider_txn (provider_txn)
);

Fíjate en dos detalles: el estado pasa por paid (llegó el webhook) y solo después por credited (recompensa aplicada en el juego). Separar esos dos estados es lo que te salva cuando la acreditación falla porque la base del juego está fuera de línea — reprocesas sin cobrar de nuevo.

Integración con PayPal (API REST + Webhook)

El PayPal moderno usa la API REST v2 con autenticación OAuth2. Obtienes un access_token con Client ID y Secret, creas una "order", rediriges al usuario y recibes el resultado por webhook. Instala el SDK oficial vía Composer:

composer require paypal/paypal-server-sdk

Para crear la orden en el backend (ejemplo simplificado con llamada directa):

<?php
// obtener token OAuth2
$ch = curl_init('https://api-m.paypal.com/v1/oauth2/token');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_USERPWD => $clientId . ':' . $secret,
    CURLOPT_POSTFIELDS => 'grant_type=client_credentials',
]);
$token = json_decode(curl_exec($ch))->access_token;

// crear la orden de pago
$payload = [
    'intent' => 'CAPTURE',
    'purchase_units' => [[
        'reference_id' => $orderId,             // tu order_id interno
        'amount' => ['currency_code' => 'BRL', 'value' => '20.00'],
    ]],
];

El punto crítico es el webhook. En el panel de PayPal Developer registras la URL https://tusitio.com/webhook/paypal.php y suscribes el evento PAYMENT.CAPTURE.COMPLETED. Al recibir la notificación, debes verificar la firma llamando al endpoint /v1/notifications/verify-webhook-signature, comparando los headers PAYPAL-TRANSMISSION-ID, PAYPAL-TRANSMISSION-SIG y el webhook_id. Solo después de eso confía en el contenido.

<?php
$body = file_get_contents('php://input');
$event = json_decode($body, true);

if ($event['event_type'] === 'PAYMENT.CAPTURE.COMPLETED') {
    $txn   = $event['resource']['id'];
    $value = $event['resource']['amount']['value'];
    $curr  = $event['resource']['amount']['currency_code'];
    $ref   = $event['resource']['custom_id'] ?? null;

    // 1. verificar firma vía API (¡obligatorio!)
    // 2. verificar valor y moneda contra el pedido guardado
    // 3. acreditar de forma idempotente
    if ($curr === 'BRL' && verificarAssinaturaPayPal($body)) {
        creditarDoacao($ref, $txn, (float)$value);
    }
    http_response_code(200);
}

Nunca acredites basándote en el retorno del navegador (return_url). Aquella redirección sirve solo para mostrar "¡Gracias!" al jugador. La verdad financiera vive en el webhook verificado.

Integración con PIX vía pasarela

El PIX puro (clave estática) no notifica a tu servidor automáticamente — por eso usamos el cobro dinámico de una pasarela (estándar PIX Cob), que genera un QR Code por pedido y dispara un webhook cuando el pago cae. El flujo genérico es: autentica en la API, crea un cobro con txid y valor, recibe el qrcode (payload copia-y-pega) y la imagemQrcode (base64), lo muestra al usuario, y espera el webhook.

<?php
// ejemplo genérico de creación de cobro PIX (varía por pasarela)
$cobranca = [
    'calendario' => ['expiracao' => 3600],
    'valor'      => ['original' => '20.00'],
    'chave'      => '[email protected]',
    'solicitacaoPagador' => "Donacion pedido #{$orderId}",
];
// POST autenticado -> retorna { txid, pixCopiaECola, location }

Cuando el pagador concluye, la pasarela llama a tu webhook (ej.: https://tusitio.com/webhook/pix.php) con el txid y el estado CONCLUIDA. La validación aquí suele hacerse por mTLS (certificado de la pasarela) o por un token secreto acordado — confírmalo en la documentación de tu proveedor. Igual que en PayPal, verifica el valor, marca como pagado y acredita:

<?php
$dados = json_decode(file_get_contents('php://input'), true);
foreach ($dados['pix'] ?? [] as $pix) {
    if (($pix['status'] ?? '') === 'CONCLUIDA') {
        creditarPorTxid($pix['txid'], (float)$pix['valor']);
    }
}
http_response_code(200);

Acreditación atómica en la base del juego

Esta es la etapa más sensible. La recompensa (WCoin, VIP) va a la base del juego (SQL Server), no a la del sitio. La función de acreditación necesita ser idempotente y transaccional: si se ejecuta dos veces para la misma transacción, acredita una sola vez.

<?php
function creditarDoacao(string $orderId, string $txn, float $valor): void
{
    global $siteDb, $gameDb;

    // traba idempotente: solo prosigue si aún no fue acreditado
    $ok = $siteDb->prepare(
        "UPDATE donations SET status='paid', provider_txn=?, paid_at=NOW()
         WHERE id=? AND status='pending'"
    );
    $ok->execute([$txn, $orderId]);
    if ($ok->rowCount() === 0) return; // ya procesado

    $row = /* buscar wcoin, vip_days, account del pedido */;

    // aplicar en la game DB (nombres de tabla/columna VARÍAN POR VERSIÓN)
    $gameDb->beginTransaction();
    $gameDb->prepare(
        "UPDATE MEMB_INFO SET WCoin = WCoin + ? WHERE memb___id = ?"
    )->execute([$row['wcoin'], $row['account']]);
    // añadir días de VIP según el sistema de tu distribución
    $gameDb->commit();

    $siteDb->prepare("UPDATE donations SET status='credited' WHERE id=?")
           ->execute([$orderId]);
}

El WHERE ... status='pending' combinado con rowCount() es el corazón de la idempotencia: si llegan dos webhooks (PayPal reenvía en caso de timeout), solo el primero cambia la fila; el segundo encuentra cero filas afectadas y sale sin acreditar de nuevo. La columna WCoin y la tabla MEMB_INFO son ejemplos típicos de Season 6 — en tu versión puede ser Cash, zen, una tabla Cash_Shop propia, o un sistema de VIP en una tabla separada. Confirma siempre.

Si quieres desacoplar aún más, el webhook solo marca paid y un cron corre cada minuto procesando pedidos paid que todavía no fueron credited. Esto hace el sistema resistente a caídas de la base del juego.

Página de donación y experiencia del jugador

En el front-end, presenta los paquetes de forma clara y ofrece ambos métodos. Un ejemplo de estructura de datos de los paquetes:

const pacotes = [
  { id: 1, label: "Principiante", brl: 10, wcoin: 2000, vip: 7 },
  { id: 2, label: "Guerrero",   brl: 20, wcoin: 5000, vip: 30 },
  { id: 3, label: "Lord",       brl: 50, wcoin: 15000, vip: 90 },
];

Al hacer clic, el front llama a tu backend, que crea el pedido pending y devuelve la URL de PayPal o el QR Code PIX. Muestra un contador de expiración del PIX y un botón "Ya pagué / Verificar" que consulta el estado del pedido (sin acreditar — solo lee el estado). Si montas tu servidor desde cero, vale la pena revisar todo el resto de la estructura en la guía cómo montar un servidor de MU Online antes de conectar el módulo de donaciones.

Errores comunes y soluciones

SíntomaCausa probableSolución
Donación pagada pero no acreditóWebhook no configurado o URL sin HTTPS válidoRegistra la URL en el panel del proveedor y prueba con certificado válido
WCoin acreditado dos vecesFalta de idempotencia; webhook reenviadoUsa UNIQUE(provider_txn) y UPDATE ... WHERE status='pending'
Acreditó valor equivocadoConfió en el valor enviado por el navegadorReconcilia siempre contra el pedido guardado en la base
Chargeback tras el créditoCuenta nueva + PayPalRegistra IP/cuenta, entrega como bien virtual, monitorea cuentas recientes
El webhook devuelve 500 y el proveedor reenvía infinitoExcepción no tratada antes del http_response_code(200)Envuelve en try/catch y responde 200 incluso en error de negocio, registrando aparte
PIX no confirmaValidación de firma/mTLS fallandoConfirma el certificado de la pasarela y el token secreto del webhook

Seguridad y cumplimiento

  • Valida siempre el origen del webhook. En PayPal, usa el endpoint de verificación de firma; en PIX, mTLS o token secreto.
  • Registra logs de cada webhook recibido (payload crudo + IP) por al menos algunos meses, para auditoría y disputa de chargeback.
  • Limita intentos y aplica rate limiting en el endpoint de creación de pedidos, evitando abuso.
  • No expongas el Client Secret en JavaScript; toda comunicación sensible queda en el backend.
  • Términos claros: deja explícito que las donaciones son para el mantenimiento del servidor y que los ítems virtuales no tienen valor monetario reembolsable, reduciendo disputas.
  • Fiscal: al profesionalizarte, considera abrir un MEI/empresa y usar una pasarela que emita comprobantes. Los ingresos recurrentes son tributables.

Lista de verificación de lanzamiento

  • HTTPS válido en el dominio y en los endpoints de webhook
  • Tabla donations creada con UNIQUE(provider_txn)
  • Credenciales de API en .env fuera de la raíz pública
  • Webhook de PayPal registrado y firma verificada en código
  • Webhook de la pasarela PIX registrado con validación (mTLS/token)
  • Función de acreditación idempotente y transaccional probada
  • Nombres reales de tabla/columna de la game DB confirmados para tu versión
  • Cron de reprocesamiento de pedidos paid no credited activo
  • Logs de webhook e IP habilitados
  • Prueba de punta a punta en sandbox (PayPal Sandbox + PIX de prueba)
  • Términos de donación publicados en el sitio

Con este flujo eliminas el crédito manual, reduces fraudes y entregas una experiencia instantánea al jugador — que dona, paga por PIX en segundos y ve el VIP en el personaje sin necesidad de abrir un ticket. Empieza siempre en un entorno de pruebas, valida la idempotencia con pagos reales de valor bajo y solo entonces libera para toda la comunidad.

Preguntas frecuentes

¿Las donaciones en MU Online son legales en Brasil?

Sí, siempre que se ofrezcan como donación voluntaria o venta de ítems virtuales cosméticos. Se recomienda transparencia en los términos, emisión de comprobantes y atención a las reglas fiscales aplicables a ingresos recurrentes.

¿Necesito CNPJ para recibir PIX de donaciones?

No es obligatorio para montos bajos y esporádicos con clave de persona física, pero al crecer el volumen lo ideal es abrir un MEI o empresa para regularizar los ingresos y usar pasarelas que exijan cuenta empresarial.

¿PayPal funciona bien para el público brasileño?

Funciona, pero muchos jugadores brasileños prefieren PIX por su instantaneidad y la ausencia de tarifas altas. Lo ideal es ofrecer ambos métodos lado a lado en el mismo panel de donación.

¿Cómo evitar fraudes de chargeback en PayPal?

Registra logs de IP y cuenta, entrega ítems marcados como bienes virtuales, mantén los términos claros y monitorea donaciones repetidas de cuentas nuevas. Los chargebacks son comunes en servidores y deben preverse.

¿Es seguro acreditar automáticamente sin revisión humana?

Sí, si validas la firma del webhook, verificas el valor y la moneda, y usas una tabla de idempotencia para no acreditar la misma transacción dos veces. Nunca confíes solo en parámetros de la URL de retorno.

GA
Editor de guías y builds

Gabriel cubre gameplay, builds de clases, PvP y progresión. Prueba cada estrategia en un servidor antes de publicar.

Sigue leyendo

Artículos relacionados