O maior portal de MU Online do Brasil — desde 2003
Tutorial Avançado Website

Como integrar doações com PayPal e PIX no servidor de MU Online

Aprenda a construir um sistema de doações completo para o seu servidor de MU Online, integrando PayPal via IPN/Webhook e PIX através de gateways brasileiros, com creditação automática de VIP e WCoin sem intervenção manual.

GA Gabriel · Atualizado em 30 jun 2025 · ⏱ 14 de leitura
Resposta rápida

Montar um sistema de doações confiável é um dos passos que mais diferencia um servidor de MU Online amador de um projeto sustentável. A maioria dos administradores começa pedindo comprovante por Discord e creditando VIP na mão, o que não escala, gera atrasos e abre espaço para erro humano e golpes.

Montar um sistema de doações confiável é um dos passos que mais diferencia um servidor de MU Online amador de um projeto sustentável. A maioria dos administradores começa pedindo comprovante por Discord e creditando VIP na mão, o que não escala, gera atrasos e abre espaço para erro humano e golpes. Neste tutorial avançado você vai construir um fluxo de doação de ponta a ponta: uma página de checkout no site, integração com o PayPal via IPN/Webhook, integração com PIX através de um gateway brasileiro (usando o padrão de cobrança dinâmica com QR Code e confirmação por webhook), e a creditação automática de recompensas no banco de dados do jogo. Todos os exemplos de nomes de tabelas, colunas e valores são apenas ilustrativos e variam por versão (Season 6, Season 16, arquivos IGCN, MuEMU, etc.) — sempre confira o schema real da sua distribuição antes de rodar qualquer SQL em produção.

O princípio central que você deve levar deste guia é simples: nunca credite recompensa com base no que o navegador do usuário te diz. A confirmação de pagamento válida vem sempre de uma notificação servidor-a-servidor, assinada e verificável, enviada pelo provedor de pagamento diretamente ao seu backend. Tudo o mais é apenas interface.

Pré-requisitos

Antes de começar, garanta que você tem o ambiente e os acessos abaixo. Sem eles, o restante do tutorial não roda.

  • Um site funcional em PHP 8.0 ou superior (idealmente 8.2+) com acesso ao composer para instalar SDKs.
  • Servidor web com HTTPS válido (Let's Encrypt já resolve). Webhooks de PayPal e de gateways PIX exigem endpoint HTTPS público — nada de localhost ou certificado autoassinado.
  • Acesso ao banco de dados do jogo (SQL Server, na maioria das distribuições de MU) e ao banco do site (MySQL/MariaDB, comum em CMS).
  • Uma conta PayPal Business (a pessoal não emite as credenciais de API REST completas).
  • Uma conta em um gateway de pagamento brasileiro que ofereça PIX via API com webhook (Mercado Pago, Efí/antigo Gerencianet, Asaas, PagSeguro, entre outros). Os exemplos usam o padrão genérico "criar cobrança → receber webhook".
  • Noções de fila/cron ou de transações SQL para garantir creditação atômica.

> Segurança: trate as credenciais de API (Client ID, Secret, tokens) como senhas. Nunca as coloque no repositório Git nem em JavaScript do front-end. Use variáveis de ambiente (.env) fora da raiz pública sempre que possível.

Arquitetura geral do fluxo

Antes de escrever código, visualize o caminho de uma doação. O jogador nunca toca no banco do jogo diretamente; ele passa por camadas que validam cada etapa.

  1. O jogador faz login no site e escolhe um pacote (ex.: R$ 20 = 5.000 WCoin + 30 dias de VIP).
  2. O backend cria um pedido pendente no banco do site, com um identificador único (order_id).
  3. O jogador é redirecionado ao PayPal ou recebe um QR Code PIX.
  4. Após pagar, o provedor envia um webhook ao seu servidor confirmando o pagamento.
  5. O backend valida a assinatura, confere valor/moeda, marca o pedido como pago e credita a recompensa no banco do jogo — tudo de forma idempotente.
  6. O jogador vê o saldo atualizado no painel.
CamadaResponsabilidadeNunca deve
Front-endExibir pacotes e iniciar o pagamentoDecidir se algo foi pago
Backend (pedidos)Criar/atualizar pedidos, gerar cobrançaCreditar sem webhook confirmado
Webhook handlerValidar assinatura e confirmarConfiar em parâmetros de retorno (?status=success)
Creditação (game DB)Adicionar VIP/WCoin de forma atômicaRodar duas vezes para a mesma transação

Modelagem da tabela de pedidos

Crie no banco do site uma tabela para rastrear cada doação. A idempotência depende dela: a coluna transaction_id do provedor deve ser única para impedir crédito duplicado.

CREATE TABLE donations (
    id            BIGINT AUTO_INCREMENT PRIMARY KEY,
    account       VARCHAR(20)  NOT NULL,          -- conta do jogo
    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)
);

Repare em dois detalhes: o status passa por paid (webhook chegou) e só depois credited (recompensa aplicada no jogo). Separar esses dois estados é o que te salva quando a creditação falha por o banco do jogo estar offline — você reprocessa sem cobrar de novo.

Integração com PayPal (API REST + Webhook)

O PayPal moderno usa a API REST v2 com autenticação OAuth2. Você obtém um access_token com Client ID e Secret, cria uma "order", redireciona o usuário e recebe o resultado por webhook. Instale o SDK oficial via Composer:

composer require paypal/paypal-server-sdk

Para criar a ordem no backend (exemplo simplificado com chamada direta):

<?php
// obter 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;

// criar a ordem de pagamento
$payload = [
    'intent' => 'CAPTURE',
    'purchase_units' => [[
        'reference_id' => $orderId,             // seu order_id interno
        'amount' => ['currency_code' => 'BRL', 'value' => '20.00'],
    ]],
];

O ponto crítico é o webhook. No painel do PayPal Developer você registra a URL https://seusite.com/webhook/paypal.php e assina o evento PAYMENT.CAPTURE.COMPLETED. Ao receber a notificação, você deve verificar a assinatura chamando o endpoint /v1/notifications/verify-webhook-signature, comparando os headers PAYPAL-TRANSMISSION-ID, PAYPAL-TRANSMISSION-SIG e o webhook_id. Só depois disso confie no conteúdo.

<?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 assinatura via API (obrigatório!)
    // 2. conferir valor e moeda contra o pedido salvo
    // 3. creditar de forma idempotente
    if ($curr === 'BRL' && verificarAssinaturaPayPal($body)) {
        creditarDoacao($ref, $txn, (float)$value);
    }
    http_response_code(200);
}

Nunca credite com base no retorno do navegador (return_url). Aquele redirecionamento serve só para exibir "Obrigado!" ao jogador. A verdade financeira mora no webhook verificado.

Integração com PIX via gateway

O PIX puro (chave estática) não notifica seu servidor automaticamente — por isso usamos a cobrança dinâmica de um gateway (padrão PIX Cob), que gera um QR Code por pedido e dispara webhook quando o pagamento cai. O fluxo genérico é: autentica na API, cria uma cobrança com txid e valor, recebe o qrcode (payload copia-e-cola) e o imagemQrcode (base64), exibe ao usuário, e aguarda o webhook.

<?php
// exemplo genérico de criação de cobrança PIX (varia por gateway)
$cobranca = [
    'calendario' => ['expiracao' => 3600],
    'valor'      => ['original' => '20.00'],
    'chave'      => '[email protected]',
    'solicitacaoPagador' => "Doacao pedido #{$orderId}",
];
// POST autenticado -> retorna { txid, pixCopiaECola, location }

Quando o pagador conclui, o gateway chama seu webhook (ex.: https://seusite.com/webhook/pix.php) com o txid e o status CONCLUIDA. A validação aqui costuma ser feita por mTLS (certificado do gateway) ou por um token secreto acordado — confirme na documentação do seu provedor. Assim como no PayPal, confira valor, marque como pago e credite:

<?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);

Creditação atômica no banco do jogo

Esta é a etapa mais sensível. A recompensa (WCoin, VIP) vai para o banco do jogo (SQL Server), não para o do site. A função de creditação precisa ser idempotente e transacional: se rodar duas vezes para a mesma transação, credita uma só vez.

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

    // trava idempotente: só prossegue se ainda não foi creditado
    $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; // já processado

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

    // aplicar no game DB (nomes de tabela/coluna VARIAM POR VERSÃO)
    $gameDb->beginTransaction();
    $gameDb->prepare(
        "UPDATE MEMB_INFO SET WCoin = WCoin + ? WHERE memb___id = ?"
    )->execute([$row['wcoin'], $row['account']]);
    // adicionar dias de VIP conforme o sistema da sua distribuição
    $gameDb->commit();

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

O WHERE ... status='pending' combinado com rowCount() é o coração da idempotência: se dois webhooks chegarem (o PayPal reenvia em caso de timeout), apenas o primeiro muda a linha; o segundo encontra zero linhas afetadas e sai sem creditar de novo. A coluna WCoin e a tabela MEMB_INFO são exemplos típicos de Season 6 — na sua versão pode ser Cash, zen, uma tabela Cash_Shop própria, ou um sistema de VIP em tabela separada. Confirme sempre.

Se você quiser desacoplar ainda mais, o webhook apenas marca paid e um cron roda a cada minuto processando pedidos paid que ainda não foram credited. Isso torna o sistema resiliente a quedas do banco do jogo.

Página de doação e experiência do jogador

No front-end, apresente os pacotes de forma clara e ofereça os dois métodos. Um exemplo de estrutura de dados dos pacotes:

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

Ao clicar, o front chama seu backend, que cria o pedido pending e devolve a URL do PayPal ou o QR Code PIX. Mostre um contador de expiração do PIX e um botão "Já paguei / Verificar" que consulta o status do pedido (sem creditar — só lê o status). Se você monta seu servidor do zero, vale revisar todo o restante da estrutura no guia como montar um servidor de MU Online antes de plugar o módulo de doações.

Erros comuns e soluções

SintomaCausa provávelSolução
Doação paga mas não creditouWebhook não configurado ou URL sem HTTPS válidoRegistre a URL no painel do provedor e teste com certificado válido
WCoin creditado em dobroFalta de idempotência; webhook reenviadoUse UNIQUE(provider_txn) e UPDATE ... WHERE status='pending'
Creditou valor erradoConfiou no valor enviado pelo navegadorSempre reconcilie contra o pedido salvo no banco
Chargeback após créditoConta nova + PayPalLogue IP/conta, entregue como bem virtual, monitore contas recentes
Webhook retorna 500 e provedor reenvia infinitoExceção não tratada antes do http_response_code(200)Envolva em try/catch e responda 200 mesmo em erro de negócio, logando à parte
PIX não confirmaValidação de assinatura/mTLS falhandoConfirme certificado do gateway e o token secreto do webhook

Segurança e conformidade

  • Valide sempre a origem do webhook. No PayPal, use o endpoint de verificação de assinatura; no PIX, mTLS ou token secreto.
  • Registre logs de cada webhook recebido (payload cru + IP) por pelo menos alguns meses, para auditoria e disputa de chargeback.
  • Limite tentativas e aplique rate limiting no endpoint de criação de pedidos, evitando abuso.
  • Não exponha Client Secret em JavaScript; toda comunicação sensível fica no backend.
  • Termos claros: deixe explícito que doações são para manutenção do servidor e que itens virtuais não têm valor monetário reembolsável, reduzindo disputas.
  • Fiscal: ao profissionalizar, considere abrir MEI/empresa e usar gateway que emita comprovantes. Receita recorrente é tributável.

Checklist de lançamento

  • HTTPS válido no domínio e nos endpoints de webhook
  • Tabela donations criada com UNIQUE(provider_txn)
  • Credenciais de API em .env fora da raiz pública
  • Webhook do PayPal registrado e assinatura verificada em código
  • Webhook do gateway PIX registrado com validação (mTLS/token)
  • Função de creditação idempotente e transacional testada
  • Nomes reais de tabela/coluna do game DB confirmados para sua versão
  • Cron de reprocessamento de pedidos paid não credited ativo
  • Logs de webhook e IP habilitados
  • Teste ponta a ponta em sandbox (PayPal Sandbox + PIX de teste)
  • Termos de doação publicados no site

Com esse fluxo você elimina o crédito manual, reduz fraudes e entrega uma experiência instantânea ao jogador — que doa, paga no PIX em segundos e vê o VIP no personagem sem precisar abrir ticket. Comece sempre em ambiente de testes, valide a idempotência com pagamentos reais de valor baixo e só então libere para toda a comunidade.

Perguntas frequentes

As doações no MU Online são legais no Brasil?

Sim, desde que ofertadas como doação voluntária ou venda de itens virtuais cosméticos. Recomenda-se transparência nos termos, emissão de comprovantes e atenção às regras fiscais aplicáveis a receitas recorrentes.

Preciso de CNPJ para receber PIX de doações?

Não é obrigatório para valores baixos e esporádicos com chave de pessoa física, mas ao crescer o volume o ideal é abrir MEI ou empresa para regularizar a receita e usar gateways que exigem conta empresarial.

O PayPal funciona bem para o público brasileiro?

Funciona, mas muitos jogadores brasileiros preferem PIX pela instantaneidade e ausência de tarifas altas. O ideal é oferecer os dois métodos lado a lado no mesmo painel de doação.

Como evitar fraudes de chargeback no PayPal?

Registre logs de IP e conta, entregue itens marcados como bens virtuais, mantenha os termos claros e monitore doações repetidas de contas novas. Chargebacks são comuns em servidores e devem ser previstos.

É seguro creditar automaticamente sem revisão humana?

Sim, se você validar a assinatura do webhook, conferir o valor e a moeda, e usar uma tabela de idempotência para não creditar a mesma transação duas vezes. Nunca confie apenas em parâmetros de URL de retorno.

GA
Editor de guias e builds

Gabriel cobre gameplay, builds de classes, PvP e progressão. Testa cada estratégia em servidor antes de publicar.

Continue lendo

Artigos relacionados