Skip to content

PHPAY-76: adicionar o gateway PagBank (PagSeguro) - #77

Merged
mariolucasdev merged 1 commit into
developfrom
feat/phpay-76
Sep 21, 2026
Merged

mariolucasdev merged 1 commit into
developfrom
feat/phpay-76

Conversation

@mariolucasdev

Copy link
Copy Markdown
Collaborator

Closes #76

Parte da v2.0.0. Base em refactor/phpay-70, onde #73 e #75 já estão mergeados.

Quarto gateway da biblioteca. Junto com o Mercado Pago, é o de maior alcance no Brasil — forte especialmente em PME e varejo.

Capacidades

Declara três das cinco:

Capacidade Declara? Endpoint / motivo
SupportsCustomers /customers (assinantes)
SupportsCharges /orders, /charges, /charges/{id}/cancel
SupportsSubscriptions /plans, /subscriptions
SupportsWebhooks Sem CRUD por API — registra-se no painel, ou por pedido via notification_urls
SupportsPixKeys Pix não é nem uma cobrança aqui (veja abaixo)

Três particularidades que nenhum gateway anterior tinha

1. Duas APIs em hosts diferentes. Pedidos e cobranças em api.pagseguro.com; planos, assinantes e assinaturas em api.assinaturas.pagseguro.com. O trait expõe clientPagBankBoot() e clientPagBankSubscriptionsBoot(), e cada recurso boota o da sua API — quem usa a biblioteca não precisa saber que são duas.

2. Pix não é uma charge. O pedido carrega qr_codes: [{amount: {value}}] em vez de charges, o copia-e-cola volta em qr_codes[0].text, e só um QR Code por pedido é aceito (a conta também precisa de uma chave Pix ativa). setQrCode() e setCharges() expressam essa diferença em vez de escondê-la atrás de um "billingType" que não existe lá.

$pedido = $phpay->charge()
    ->setCustomer($customer)
    ->addItem('Assinatura PHPay', 10050)   // R$ 100,50
    ->setQrCode(10050)
    ->create();

$phpay->charge()->getPixCode($pedido['id']);

3. Todo valor é inteiro em centavos. R$ 100,50 é 10050. Mandar 100.50 cobraria um real. Os validadores recusam decimal antes de qualquer chamada, com mensagem dizendo a conversão — é o erro mais fácil de cometer com essa API e o mais caro de descobrir em produção.

Decisões de modelagem

  • Cliente do pedido vs. assinante. No pedido o cliente vem embutido; o CRUD de /customers é de assinantes e pertence ao domínio de recorrência, por isso vive no host de assinaturas. SupportsCustomers diz "tem o recurso", não "é o mesmo cliente do pedido".
  • Planos no recurso Subscription. Uma assinatura sempre pertence a um plano — é um fluxo só. Criar um recurso Plan separado exigiria uma capacidade nova para pouco ganho.

Recursos

  • ChargesetOrder, setCustomer, setItems/addItem, setCharges, setQrCode, setNotificationUrls, create, find, findCharge, getStatus, getPixCode, refund total ou parcial
  • Customercreate, find, update, getAll, setFilter
  • SubscriptioncreatePlan, findPlan, getAllPlans, create, find, getAll, suspend, activate, cancel

Verificação

123 testes (307 asserções), PHPStan nível 9 limpo, Pint limpo. Os do PagBank cobrem o roteamento de cada recurso para o host certo, o Pix indo como qr_code e não como charge, a recusa de valor decimal, a recusa de mais de um QR Code, e as rotas de suspender/reativar/cancelar.

Inclui examples/pagbank/sandbox-check.php, que roda contra o sandbox de verdade e relata cada operação — teste com HTTP mockado prova que montamos o payload que decidimos, não que o gateway o aceita.

Endpoints, o modelo qr_codes e a unidade em centavos foram conferidos na documentação oficial do PagBank, não escritos de memória.

Quarto gateway da biblioteca. Declara três das cinco capacidades:

  SupportsCustomers     /customers  (assinantes)
  SupportsCharges       /orders, /charges
  SupportsSubscriptions /plans, /subscriptions

Não declara SupportsWebhooks porque o PagBank não expõe CRUD de webhooks por
API — eles são registrados no painel, ou por pedido via notification_urls. Não
declara SupportsPixKeys porque lá o Pix não é sequer uma cobrança.

Três particularidades que nenhum gateway anterior tinha:

1. Duas APIs em hosts diferentes. Pedidos e cobranças vivem em
api.pagseguro.com; planos, assinantes e assinaturas em
api.assinaturas.pagseguro.com. O trait expõe clientPagBankBoot() e
clientPagBankSubscriptionsBoot(), e cada recurso boota o da sua API — quem usa
a biblioteca não precisa saber que são duas.

2. Pix não é uma charge. O pedido carrega qr_codes: [{amount: {value}}] em vez
de charges, o copia-e-cola volta em qr_codes[0].text, e só um QR Code por
pedido é aceito. setQrCode() e setCharges() expressam essa diferença em vez de
escondê-la atrás de um "billingType".

3. Todo valor é inteiro em centavos. R$ 100,50 é 10050, e mandar 100.50 cobraria
um real. Os validadores recusam decimal antes de qualquer chamada, com mensagem
dizendo a conversão — é o erro mais fácil de cometer com essa API e o mais caro
de descobrir em produção.

O cliente do pedido vem embutido nele; o CRUD de /customers é de assinantes, do
domínio de recorrência, e por isso vive no host de assinaturas. Planos ficam no
recurso Subscription em vez de virarem recurso próprio: uma assinatura sempre
pertence a um plano, é um fluxo só.

123 testes no total. Os do PagBank cobrem o roteamento de cada recurso para o
host certo, o Pix indo como qr_code e não como charge, a recusa de valor
decimal, a recusa de mais de um QR Code, e as rotas de suspender, reativar e
cancelar assinatura.

Inclui também examples/pagbank/sandbox-check.php, que roda contra o sandbox de
verdade e relata cada operação — teste com HTTP mockado prova que montamos o
payload que decidimos, não que o gateway o aceita.
Base automatically changed from refactor/phpay-70 to develop September 21, 2026 00:38
@mariolucasdev
mariolucasdev merged commit 6e8d9ac into develop Sep 21, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Adicionar o gateway PagBank (PagSeguro)

1 participant