PHPAY-95: Efí — API Pix com mTLS, de 1 para 4 capacidades - #96
Merged
Merged
Conversation
A API Pix do BACEN quer o valor em reais como string com ponto e duas casas ("123.45"), que não é nem toReais() (float) nem toCentavos() (int). Montado com aritmética inteira, sem float no caminho.
O padrão do BACEN para API Pix exige mTLS em toda requisição, inclusive na de token. A Efí é a primeira a precisar disso aqui, e Inter, BB, Itaú, Sicoob e Sicredi usam o mesmo esquema, por isso o certificado mora em Http e não dentro de um gateway. - Certificate valida existência e formato (.p12/.pem, que o Guzzle entrega ao cURL pela extensão) - fromBase64() para containers e serverless, gravando num temporário 0600 removido ao fim do processo - __debugInfo() mascara a senha - HasHttpClient ganha patch() e headers por requisição no put()
O token ficava em cache para sempre, mas a Efí o expira (expires_in). Um gateway vivo num worker de fila passava a tomar 401 depois de alguns minutos. Agora o prazo anunciado é respeitado, com a mesma margem de 30s da Rede. Sem expires_in, o comportamento antigo se mantém.
…ico e cobrança Pix
A Efí tem uma segunda API, a API Pix, em outro host (pix.api.efipay.com.br / pix-h.api.efipay.com.br) e só por mTLS. Com ela o gateway vai de 1 para 4 capacidades:
- SupportsPixKeys: chaves aleatórias (EVP) em /v2/gn/evp
- SupportsWebhooks: um webhook por chave Pix, com skipMtlsChecking() para servidor que não valida o certificado da Efí
- SupportsSubscriptions: Pix Automático, com a recorrência (/v2/rec), o location da jornada de QR Code (/v2/locrec) e a cobrança de cada ciclo (/v2/cobr)
- pixCharge(): cobrança imediata (cob) e com vencimento (cobv), QR Code e devolução. É um extra do gateway concreto, porque charge() já é o boleto e mudar o retorno quebraria a v2
Decisões:
- O mesmo EfiGateway, com as mesmas credenciais. O certificado entra como parâmetro opcional novo (caminho ou Certificate), então nada quebra
- Cada API tem o seu token, em cache e renovado ao expirar
- Valor só como Money: a API Pix quer reais ("123.45") e a de Cobranças do mesmo gateway quer centavos, então número cru aqui seria justamente a ambiguidade que o Money existe para eliminar
- O certificado só é exigido quando a biblioteca monta o próprio client. Sem ele, o erro é claro em vez de uma falha de handshake TLS
- Guzzle ^7.3, a primeira versão que entrega .p12 ao cURL pela extensão
Rotas e métodos conferidos no SDK oficial (efipay/sdk-php-apis-efi, src/Efi/Endpoints/Pix.php). Status de cancelamento, periodicidades e campos obrigatórios conferidos na especificação do BACEN (bacen/pix-api, openapi.yaml).
- README: o Efí sobe para 4 capacidades nas tabelas, ganha uma seção com as duas APIs, o certificado (caminho, senha e base64) e exemplos de cobrança Pix, chaves, webhooks e Pix Automático. O exemplo de gateway restrito em Capacidades passa a ser a Rede - CLAUDE.md: as particularidades do Efí, uma seção de mTLS e os itens que ficaram de fora (jornada 1, webhookrec/webhookcobr, envio de Pix). A visão geral também passa a citar o Woovi, que estava faltando - examples/efi/pix.php, com CERTIFICATE e PIX_KEY no credentials.example.php - .gitignore passa a ignorar certificados (.p12, .pfx, .pem)
… @phpstan-assert Tira o @var inline do Webhook::create(): quem valida é quem garante o tipo, e o PHPStan passa a saber disso pelo contrato do validador.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #95.
O que muda
O Efí passa de 1 para 4 capacidades com a API Pix, que roda em outro host e só aceita mTLS:
pix()/v2/gn/evp: criar, listar e remover EVPwebhook()/v2/webhook/:chave, um por chave, comskipMtlsChecking()subscription()/v2/rec,/v2/locrece/v2/cobrpixCharge()cob(imediata) ecobv(com vencimento), QR Code e devoluçãoClientes continuam fora, porque nenhuma das duas APIs do Efí mantém cadastro de cliente.
Commits
feat(money):Money::toDecimal()devolve"123.45", o formato do padrão Pix do BACEN, montado com aritmética inteira.feat(http):PHPay\Http\Certificate, genérico, porque Inter, BB, Itaú, Sicoob e Sicredi usam o mesmo esquema de mTLS. Aceita.p12/.pem,fromBase64()para container e serverless (temporário 0600, apagado ao fim do processo), e__debugInfo()mascara a senha. OHasHttpClientganhapatch()e headers noput().fix(efi): o token da API de Cobranças ficava em cache para sempre. Um gateway vivo num worker de fila passava a tomar 401 quando o Efí o expirava, e agora oexpires_iné respeitado.feat(efi): a API Pix em si.doc(efi): README, CLAUDE.md,examples/efi/pix.phpe.gitignorepara certificados.refactor(efi):@phpstan-assertno validador de webhook, no lugar de@varinline.Decisões que merecem revisão
pixCharge()é um extra do gateway concreto, como owebhookDeliveries()do Pagar.me. Ocharge()da facade já é o boleto, e mudar o retorno dele quebraria a v2.Money, semint. Ela quer reais e a API de Cobranças do mesmo gateway quer centavos, então aceitar número cru criaria exatamente a ambiguidade que oMoneyexiste para eliminar. Como a API é nova, não há compatibilidade a manter.^7.0→^7.3, a primeira versão que entrega.p12ao cURL pela extensão. Não usoCURLOPT_SSLCERTTYPEemcurlporque o Guzzle recente recusa opção cURL que conflite com as dele. É um piso de dependência que sobe; convém citar na release.ValidationExceptionclara, em vez de uma falha de handshake TLS.Fontes
efipay/sdk-php-apis-efi, arquivosrc/Efi/Endpoints/Pix.phpexamples/pix/REMOVIDA_PELO_USUARIO_RECEBEDOR,CANCELADA), periodicidades e campos obrigatórios do Pix Automático: especificação do BACENbacen/pix-api, arquivoopenapi.yamlComo testar
composer testroda 331 testes, 910 asserções, todos com HTTP mockado. Os 56 testes novos cobrem:cob,cobv,rececobrno formato do BACEN, e as validações que barram antes de qualquer chamada HTTPAinda não foi exercitado contra o sandbox real: o teste mockado prova o payload que decidimos, não que o Efí o aceita. Para isso é preciso o certificado de homologação da conta.
examples/efi/pix.phpjá está pronto para esse teste.Ficou de fora
Pix Automático pela jornada 1 (
solicrec), webhooks de recorrência (webhookrec,webhookcobr), envio de Pix e split. Está registrado no CLAUDE.md.Checklist
composer testpassa (Pint, Pest e PHPStan nível 9)Nada quebra: o certificado e o
pixClientsão parâmetros novos e opcionais no fim do construtor.