PHIZCHAT← RFCsRFC PHZ-0002RascunhoDraft草稿
v1.0

Histórico de versõesVersion history版本历史

RFC PHZ-0002 · Rascunho para revisão

Migração da integração CredPay para a API GruPag

Troca das rotas atuais da CredPay, espalhadas em quatro APIs com logins diferentes, pela nova API GruPag: uma base, uma API Key, valores em centavos e um contrato único para cartão, 3DS, pré-autorização e PIX. A virada é feita operação por operação, pela configuração de rotas do painel interno, sem desligar o caminho antigo antes da validação.

Status
Rascunho
Autor
Gleison (Engenharia PHIZ)
Data
16/10/2026
Revisores
Pedro Bettani (Brasil)
Luciana Geromel (Brasil)
Richard Liang (China)
Henry Wu (China)
Sistemas
channel · card-vault · backapply

01Resumo

A CredPay publicou uma API nova, documentada no portal GruPag (api2.grupag.com.br). Hoje falamos com a CredPay por oito integrações em dois serviços, com quatro formas de login. Esta RFC propõe:

  • Um adaptador novo no phiz-microwd-channel, ao lado do antigo, com códigos de serviço próprios e autenticação por API Key.
  • A troca do cliente CredPay no phiz-pay-card-vault pelo contrato novo de cartão.
  • Virada controlada pela tabela route_cfg, que o operador já edita no painel interno. Cada operação muda de caminho com uma linha de configuração e volta da mesma forma, sem deploy.
  • Cinco fases, começando pelo PIX, que é o fluxo mais simples, e deixando para o fim o 3DS, que muda também o front.

A RFC também lista o que a API nova não cobre: maquininha (TEF), extrato para conciliação, transferência bancária e listagens. Essas operações ficam na integração antiga até a CredPay responder às perguntas em aberto.

8integrações CredPay hoje
4 → 1formas de autenticação
31rotas atuais mapeadas
6operações sem equivalente

02Contexto: como funciona hoje

A CredPay atende cartão (checkout, cartão salvo, pré-autorização, 3DS), PIX por QR Code e a maquininha dos comerciantes. Nenhum serviço do app fala com ela diretamente: o pedido passa pela cadeia de serviços até o channel, que é o único que conhece a CredPay, junto com o cofre de cartões.

flowchart LR
  APP["phiz-flutter
app"] --> AS["microwd-appserver
API do app"] AS --> BA["microwd-backapply
escolhe a rota"] BA --> CH["microwd-channel
fala com os canais"] CH --> CP[("CredPay
4 APIs")] CH --> CV["pay-card-vault
cofre de cartões"] CV --> CP IF["phiz-inner-front
painel"] --> IN["phiz-inner"] IN --> DB[("route_cfg
road_info")] DB -. "lê a rota" .-> BA DB -. "lê a URL" .-> CH

Linhas tracejadas são leituras de configuração. O painel não participa do pagamento: define as regras antes e mostra o resultado depois.

Como uma operação chega à CredPay

  1. O backapply procura em route_cfg a rota para o tipo de transação, a forma de pagamento e o BIN do cartão (RoadRouteServiceImpl.getRouteByTranPayAcct). A rota diz qual canal e qual código de serviço atendem.
  2. O channel recebe o código (por exemplo B21, pagamento com cartão salvo) e executa o serviço Spring registrado com esse nome.
  3. O serviço busca a URL base do canal em road_info e chama a CredPay.
Por que isso importa para a migração

Como a escolha do caminho mora em dados, e não em código, dá para colocar o caminho novo em produção desligado e ligá-lo por comerciante e por operação. Voltar atrás é trocar a linha de novo.

03Integrações atuais

Levantamento no código do phiz-microwd-channel e do phiz-pay-card-vault.

#IntegraçãoOnde estáLoginCódigos de serviço
1Checkout e cartão salvoCheckOutTokenServiceImpl, CheckOutOperationServiceImpl, credPayRefactor/POST /AuthCredPayB20–B25, B02, B03, Z519, Z520, Z523
2Pré-autorizaçãoPreAuthServiceo do checkoutB26, B27, B28
3PIX, QR e transferênciaservice/credpay/POST /oauth/tokenB10–B13
4Cartão com 3DSThreeDomainSecurePaymentServiceautenticacao/gerar-tokenB61–B70
5Maquininha (TEF)TefServiceo do checkoutB47, B48
6ConciliaçãoSynChannelDataService, Credpay*ReconciliationJob/AuthCredPay/, URL fixajobs
7Tokenização do cofrecard-vault: CredpagamentosClientPOST /AuthCredPay—
8Validação de cartãocard-vault: CredpayClient/v1/autenticacao/gerar-token—
A confirmar na Fase 0

O código mostra o que pode ser chamado. Quais códigos estão ativos em produção depende de route_cfg, que ainda não foi consultada. Esse levantamento é o primeiro passo da implementação.

04A API nova

A documentação fica no portal GruPag (exige login) e tem quatro partes: Acesso e API Key, APIs PIX, API Compra com Cartão e API de Simulação.

flowchart LR
  subgraph HOJE["Hoje"]
    direction TB
    A1["/AuthCredPay
checkout · TEF · cofre"] A2["/oauth/token
PIX"] A3["autenticacao/gerar-token
3DS"] A4["api-services /AuthCredPay
conciliação"] end subgraph NOVO["API GruPag"] K["Authorization: Bearer gpk_…
Cliente-Id: empresa"] end HOJE ==> NOVO

Quatro logins com token, cache e renovação viram uma chave fixa enviada em toda chamada.

Regras gerais

TemaComo funciona
Basehttps://api2-homolog.grupag.com.br (homologação) e https://api2.grupag.com.br (produção)
AutenticaçãoAPI Key gpk_… no header Authorization: Bearer. Uma por usuário do portal, sem validade e sem renovação. Regenerar invalida a anterior na hora.
EmpresaHeader Cliente-Id escolhe a empresa vinculada. Sem ele, vale a empresa principal. Precisa ser igual em todas as chamadas do fluxo.
ValoresCartão: centavos em string ("15000"). PIX: reais em decimal (15.00). Simulação: centavos em inteiro.
IdempotênciaCartão: pelo orderId, e duas chamadas simultâneas dão 409. PIX: mesmo valor numa janela curta dá 409.
RespostasO envelope muda por família (details, data ou campos na raiz). Erro sempre com {message}. 502: sem destino. 504: provedor não respondeu.
HTTP
# Today: four different logins, each with its own token and renewal
POST {road_info.url}/AuthCredPay            # checkout, pre-auth, TEF, card-vault
POST {road_info.url}/oauth/token            # PIX and bank transfer
POST {road_info.url}autenticacao/gerar-token # 3DS (platform API)
POST https://api-services.credpay.com.br/AuthCredPay/   # reconciliation (hard-coded URL)
BASH
# New: one API Key (gpk_...) on every call, no login, no renewal
curl -X GET "https://api2-homolog.grupag.com.br/v1/pagamento/consulta/nit?nit=$NIT" \
  -H "Authorization: Bearer $GRUPAG_API_KEY" \
  -H "Cliente-Id: $CLIENTE_ID"   # same value on every call of the flow

05Objetivos e fora de escopo

Objetivos

  • Levar cartão, cartão salvo, 3DS, pré-autorização e PIX para a API nova, sem perder nenhuma operação que hoje está ativa.
  • Trocar os quatro logins e o CredPayAuthTask por uma API Key guardada no cofre de segredos.
  • Virar e desvirar cada operação por configuração, por comerciante, sem deploy.
  • Concentrar conversões de valor e de status num único adaptador.

Fora do escopo

  • Usar a API de Simulação para mostrar parcelas e taxas no app. É uma melhoria possível, não um requisito da migração.
  • TEF, conciliação e transferência bancária, enquanto não houver equivalente na API nova.
  • Outros canais (Pinbank, Cronos, Afro).

06Mapeamento rota a rota

equivalente mesma operação, ajuste de formatomuda regra ou fluxo diferentenovo não existiasem equivalente fica no antigo

Cartão salvo e checkout

HojeAPI novaSituaçãoO que muda
POST /Tokenizacao/CriarToken
B20 · Z519
POST /v1/pagamento/cartao/adicionarmudaExige authorizerId. Um token vale para uma autorizadora só: crédito e débito precisam de tokens separados. Guardar o customerId.
GET /Tokenizacao/Obter/{id}POST /v1/pagamento/cartao/buscarmudaDevolve só o status (ATV ou INA).
GET /Tokenizacao/Listar—sem equivalenteVer Lacunas.
POST /Tokenizacao/Excluir/{id}
B24 · Z520
DELETE /v1/pagamento/cartao/removerequivalenteDELETE com corpo {token, customer}.
POST /Tokenizacao/Pagar
B21 · B02
POST /v1/pagamentomudaCentavos em string; orderId obrigatório e idempotente; devolve o nit, nova chave da transação.
POST /Tokenizacao/Cancelar/{transacaoId}/{referenceId}
B25 · B03
DELETE /v1/pagamento/cancelarmudaCorpo {nit, amount}, aceita parcial. Estorno só até 23:59 do dia da captura.
GET /Consulta/TransactionId/{id}
GET /Consulta/NumeroInterno/{n}
B22 · Z523
GET /v1/pagamento/consulta/nit?nit=mudaSó por nit. Não há busca por número interno nem por orderId.
GET /Consulta/Subdominio/Datas/{ini}/{fim}—sem equivalenteUsado na conciliação.
JSON
{
  "nomeDoCliente": "JOAO DA SILVA",
  "documento": "12345678901",
  "quantidadeDeParcelas": 1,
  "valorInicial": 150.0,
  "token": "TOKEN_DO_CARTAO",
  "numeroInterno": "PED-4711",
  "subDominioId": 1234,
  "lojaId": 1
}
JSON
{
  "merchantChargeId": "20260901010707410895669",
  "orderId": "PED-4711",
  "installments": "1",
  "authorizerId": "2",
  "amount": "15000",
  "typeTransaction": "C",
  "card": {
    "token": "crd_d6dc9c299d15…"
  }
}

Mesmo pagamento com cartão salvo, antes e depois. O valor passa de reais para centavos, e o número interno vira orderId.

Pré-autorização

HojeAPI novaSituaçãoO que muda
POST /Transacao/Autorizar
B26
POST /v1/pagamento/preautorizacaoequivalenteMesmo corpo do pagamento; nasce AUTORIZADO.
POST /Transacao/Capturar/{transacaoId}/{referenceId}/{valor}
B27
POST /v1/pagamento/preautorizacao/liquidarequivalenteCorpo {nit, amount}; aceita captura parcial.
POST /Transacao/Cancelar/{transacaoId}/{referenceId}
POST /Transacao/Cancelar/Parcial
B28
DELETE /v1/pagamento/cancelarequivalenteUm endpoint; o valor define se é parcial. Desfazer reserva não tem limite de horário.

Cartão com 3DS

HojeAPI novaSituaçãoO que muda
cartao/adicionar/
B62
POST /v1/pagamento/cartao/adicionarmudaComo no cartão salvo.
cartao/validar/ · 3ds/checar/
B61 · B69
POST /v1/pagamento/cartao/buscarmudaConfirmar se "validar" faz hoje mais do que checar status.
pagamento/cartao/3ds/configurar/
B63
POST /v1/pagamento/3ds/autenticacao
POST /v1/pagamento/3ds/configuracao
mudaVira duas chamadas. A primeira gera o merchantChargeId.
pagamento/cartao/3ds/desafio/
B64
passos no navegadormuda3DS Method e desafio são formulários enviados pelo navegador do pagador. Ver seção 07.
pagamento/cartao/3ds/checar/desafio/
B65
GET /v1/pagamento/3ds/consultar3DSequivalenteAprovado quando vêm eci e authentication.value.
pagamento/cartao/3ds/cobrar/
B66
POST /v1/pagamento + merchantChargeIdmudaA autenticação vale 15 minutos e é consumida na cobrança.
pagamento/cartao/3ds/preautorizada/cobrar/
B67
POST /v1/pagamento/preautorizacao (+ /liquidar)equivalente—
pagamento/cartao/3ds/cancelar/
B68
DELETE /v1/pagamento/cancelarmudaRegra de 23:59.
pagamento/cartao/3ds/consultar/GET /v1/pagamento/consulta/nitequivalente—

PIX

HojeAPI novaSituaçãoO que muda
POST /api/generate-qrcodes
B10
POST /transacional/pix/qrcodeequivalenteReais em decimal. Síncrono, até 30 s.
GET /api/find-qrcode/{id}
B11
GET /transacional/pix/consulta/{transactionId}equivalentePago quando o status é CONFIRMADO. Sem webhook documentado.
POST /api/bank-transfers
B12
—sem equivalente—
POST /api/list-transactions
B13
—sem equivalente—
—POST /transacional/pix/cancelamento/{transactionId}novoAté 24 h devolve na hora; depois abre disputa.
—POST /transacional/pix/disputanovoSó perfil Admin. Candidato a tela no painel.

Cofre de cartões

HojeAPI novaSituaçãoO que muda
POST /Tokenizacao/CriarTokenPOST /v1/pagamento/cartao/adicionarmudaExige authorizerId.
GET /Tokenizacao/ObterDadosToken/{token}POST /v1/pagamento/cartao/buscarmudaSó status. Confirmar se o cofre usa outro dado dessa resposta.
POST /Tokenizacao/Excluir/Token/{token}DELETE /v1/pagamento/cartao/removerequivalente—
POST /v1/pagamento (validação)POST /v1/pagamentoequivalenteMesmo caminho; muda a base e a autenticação, e passa a exigir orderId.

07Novo fluxo de cartão com 3DS

A maior mudança de fluxo está no 3DS. Hoje o backapply devolve uma URL pronta (certifyUrl, em CardCertifyServiceImpl) e o front só a abre. Na API nova, dois passos rodam no navegador do pagador, e o front precisa montar e enviar os formulários.

sequenceDiagram
  autonumber
  participant F as Front do pagador
  participant BA as backapply
  participant CH as channel
  participant G as API GruPag
  participant E as Banco emissor
  BA->>CH: iniciar 3DS do pedido
  CH->>G: POST /3ds/autenticacao
  G-->>CH: merchantChargeId e threeDsMethod
  CH-->>BA: dados do 3DS Method
  BA-->>F: dados para o navegador
  F->>E: 3DS Method em iframe invisível
  BA->>CH: autenticar com dados do navegador
  CH->>G: POST /3ds/configuracao
  G-->>CH: frictionless ou desafio
  F->>E: desafio com creq, se houver
  CH->>G: GET /3ds/consultar3DS
  G-->>CH: eci e CAVV
  CH->>G: POST /v1/pagamento com merchantChargeId
  G-->>CH: nit e status CONFIRMADO

O mesmo Cliente-Id precisa ir em todas as chamadas à API GruPag deste fluxo. Se ele faltar em uma, o pagamento responde "3DS não encontrado".

Impacto no front

Ainda falta identificar qual front abre a certifyUrl hoje (o app ou um formulário web). Ele precisa coletar os dados reais do navegador (tela, fuso, user-agent), enviar o 3DS Method num iframe invisível e apresentar o desafio num iframe de 400×650.

08Novo fluxo PIX

O PIX quase não muda de forma: gerar, consultar até pagar. O que entra de novo é a devolução com regra de prazo e a disputa.

sequenceDiagram
  autonumber
  participant CH as channel
  participant G as API GruPag
  participant P as Pagador
  CH->>G: POST /transacional/pix/qrcode
  G-->>CH: transactionId e copia-e-cola
  CH-->>P: QR Code
  P->>G: paga no banco
  loop até CONFIRMADO ou EXPIRADO
    CH->>G: GET /transacional/pix/consulta/{id}
    G-->>CH: status
  end
stateDiagram-v2
  [*] --> GERADO
  GERADO --> CONFIRMADO: pagamento
  GERADO --> EXPIRADO: venceu
  CONFIRMADO --> ESTORNANDO: devolução até 24 h
  ESTORNANDO --> ESTORNADO
  CONFIRMADO --> DISPUTA: devolução após 24 h
  DISPUTA --> CANCELANDO: admin aprova
  CANCELANDO --> CANCELADO
  DISPUTA --> PAGO: admin nega

Status de uma cobrança PIX na API nova. A disputa é decidida por um usuário Admin, o que pede uma tela no painel interno.

BASH
curl -X POST "https://api2-homolog.grupag.com.br/transacional/pix/qrcode" \
  -H "Authorization: Bearer $GRUPAG_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "amount": 15.00, "description": "Pedido PED-12345", "expirationSeconds": 3600 }'
# 200 → { "transactionId": "a1b2…", "status": "GERADO", "pixCopyAndPaste": "000201…", "destination": "TRANSACIONAL-PIX-SICREDI" }

09Lacunas

Estas operações não aparecem na documentação nova. Continuam na integração atual até a CredPay dizer qual é o substituto.

OperaçãoUso hojeImpacto se for desligada
Maquininha TEF: /Pdv/CriarOperacao, /Pdv/GetOperacaoVenda presencial (B47, B48)Para a venda em POS da CredPay.
Extrato: /Movimentacao/Analitico, /Consulta/Subdominio/DatasConciliação diáriaA conciliação deixa de conferir o canal.
Transferência bancária: /api/bank-transfersB12Para a transferência por esse canal.
Listagens: /Tokenizacao/Listar, /api/list-transactionsConsulta e sincronizaçãoPassamos a depender só dos nossos registros.
RecorrênciaCampos de recorrência no CheckOutPayReqA doc cita contrato de recorrência, sem documentar as rotas.
Webhooks—Confirmação só por consulta, o que mantém o polling.

10Mudanças que quebram contrato

MudançaHojeAPI novaO que fazer
Tokens de cartãoCriados em /Tokenizacao/CriarTokenNão está claro se valem em /v1/pagamentoConfirmar com a CredPay. Se não valerem, retokenizar pelo cofre antes da Fase 2.
ValoresReais em BigDecimal (valorInicial)Cartão em centavos (string); PIX em reaisConverter num único ponto do adaptador.
IdentificadorestransacaoId, referenceId, numeroInternonit, merchantChargeId, customerIdNovas colunas no pedido e no cartão.
Prazo de estornoSem limite documentadoCartão: até 23:59 do dia. PIX: depois de 24 h vira disputa.Tratar no app e no painel; rotina para devolução fora da API.
EmpresasubDominioId, lojaIdHeader Cliente-IdMapear cada comerciante; resolver uma vez por pedido e reutilizar.
3DSURL prontaFormulários no navegadorMudar o front.
StatusRótulos do checkoutCONFIRMADO, AUTORIZADO, PENDENTE, NEGADO…Tabela de conversão no adaptador.
JAVA
// Single conversion point in the channel's GruPag adapter
static String toCents(BigDecimal reais) {           // card: cents as a string
    return reais.setScale(2, RoundingMode.UNNECESSARY).movePointRight(2).toPlainString();
}
static BigDecimal toPixReais(BigDecimal reais) {      // PIX: reais as a decimal
    return reais.setScale(2, RoundingMode.UNNECESSARY);
}

11Proposta técnica

Um provedor novo, ao lado do antigo

Em vez de alterar os serviços atuais, o channel ganha um adaptador novo (service/grupag/) com códigos de serviço próprios e um road_info apontando para api2.grupag.com.br. Os dois caminhos convivem; a rota decide qual é usado.

flowchart LR
  BA["backapply"] --> RC{"route_cfg
por comerciante
e operação"} RC -- "código antigo" --> OLD["Serviços CredPay atuais
B10 · B21 · B61 …"] RC -- "código novo" --> NEW["Adaptador GruPag
códigos novos"] OLD --> CP[("APIs CredPay atuais")] NEW --> GP[("api2.grupag.com.br")] OP["Operador no painel"] -. "troca a linha
para virar ou voltar" .-> RC

Virar uma operação é editar route_cfg no painel. Voltar é desfazer a edição.

Mudanças por repositório

RepositórioMudança
phiz-microwd-channelCliente HTTP com API Key e Cliente-Id; adaptadores de cartão, 3DS, pré-autorização e PIX; conversão de valor e status; registro dos códigos novos.
phiz-pay-card-vaultTrocar CredpagamentosClient e CredpayClient pelo contrato novo, atrás de configuração.
phiz-microwd-backapplyGravar nit, merchantChargeId e customerId; adaptar CardCertifyServiceImpl ao 3DS novo; tratar o prazo de estorno.
phiz-microwd-commonColunas novas nas entidades de pedido e de cartão.
phiz-inner e phiz-inner-frontCadastro dos códigos e do road_info; tela de disputa PIX.
Front do 3DS3DS Method e desafio no navegador.
Credencial

A API Key não expira, mas regenerar derruba a anterior sem aviso. Ela fica no cofre de segredos de cada ambiente, nunca no código nem em texto puro no road_info, e é trocada numa janela combinada.

BASH
# Full or partial refund (card). Only until 23:59 on the capture day (Brasília time).
curl -X DELETE "https://api2-homolog.grupag.com.br/v1/pagamento/cancelar" \
  -H "Authorization: Bearer $GRUPAG_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "nit": "pag_59c416ca3552…", "amount": "5000" }'

12Plano de migração

FASE 0
Preparação
  • Levantar códigos CredPay ativos em route_cfg
  • Chave de homologação
  • Respostas da CredPay, principalmente sobre tokens
FASE 1
PIX
  • Gerar QR e consultar
  • Um comerciante de teste
  • Devolução e disputa
FASE 2
Cartão sem 3DS
  • Tokenização, pagamento, cancelamento, consulta
  • Cofre de cartões
  • Retokenização, se preciso
FASE 3
3DS
  • Fluxo novo no channel
  • Mudança no front
FASE 4
Pré-autorização
  • Reservar, liquidar, desfazer
FASE 5
Desligamento
  • Remover códigos antigos
  • Remover CredPayAuthTask e clientes antigos
  • TEF e conciliação seguem até haver substituto

Em cada fase

  1. Testes de contrato em homologação, usando a coleção Postman da CredPay como referência.
  2. Um comerciante piloto em produção, virado pela rota.
  3. Acompanhar taxa de aprovação, erros 4xx/5xx por código e tempo de resposta, comparando com o caminho antigo.
  4. Virar o restante dos comerciantes em lotes.

Datas serão definidas depois da Fase 0, quando soubermos o que está ativo e o que a CredPay respondeu.

13Riscos

RiscoMitigação
Tokens antigos não valem na API novaConfirmar na Fase 0; se for o caso, retokenizar pelo cofre antes da Fase 2.
Cliente-Id diferente no meio do fluxoResolver uma vez por pedido, gravar e reutilizar; teste automatizado do fluxo 3DS completo.
Erro de unidade (reais × centavos)Conversão num único ponto, com testes de contrato por endpoint.
Estorno recusado depois das 23:59Avisar no app e no painel; rotina de devolução fora da API.
Conciliação sem fonte de dadosManter o extrato antigo até haver substituto.
Homologação apontando para produçãoO card-vault hoje usa a base de produção como padrão porque o sandbox estava quebrado. Na API nova, exigir a base de homologação fora de produção.

14Perguntas em aberto para a CredPay

  1. Tokens. Tokens criados em /Tokenizacao/CriarToken e no cofre valem em /v1/pagamento? Existe migração em lote?
  2. Lacunas. Qual o substituto para TEF, extrato, transferência bancária e listagem de transações?
  3. Webhooks. Há notificação de confirmação para PIX e cartão, ou só consulta?
  4. Recorrência. Quais são as rotas do contrato de recorrência citado na documentação?
  5. Simulação. O hashSimulacao é conferido no pagamento? A página de simulação diz que sim; a de cartão diz que é aceito e ignorado.
  6. Empresas. Como mapear nossos comerciantes para Cliente-Id: uma chave por ambiente com todos vinculados, ou uma por comerciante?
  7. Limites. Há limite de requisições por chave?
  8. Prazo. Quando as APIs atuais serão desligadas?

15Referências

  • Documentação GruPag (exige login): Acesso e API Key, APIs PIX, API Compra com Cartão, API de Simulação.
  • channel: CheckOutTokenServiceImpl, CheckOutOperationServiceImpl, PreAuthService, service/credpay/impl/*, ThreeDomainSecurePaymentService, TefService, SynChannelDataService, ApiCodeConstant.
  • card-vault: CredpagamentosClient, CredpayClient, application.yaml.
  • backapply: RoadRouteServiceImpl, CardCertifyServiceImpl.
RFC PHZ-0002 · Draft for review

Migrating the CredPay integration to the GruPag API

Replace today's CredPay routes, spread across four APIs with different logins, with the new GruPag API: one base URL, one API Key, amounts in cents and a single contract for card, 3DS, pre-authorization and PIX. The cutover happens one operation at a time, through the route configuration in the internal panel, and the old path stays on until each operation is validated.

Status
Draft
Author
Gleison (PHIZ Engineering)
Date
2026-10-16
Reviewers
Pedro Bettani (Brazil)
Luciana Geromel (Brazil)
Richard Liang (China)
Henry Wu (China)
Systems
channel · card-vault · backapply

01Summary

CredPay has published a new API, documented in the GruPag portal (api2.grupag.com.br). Today we talk to CredPay through eight integrations in two services, with four different logins. This RFC proposes:

  • A new adapter in phiz-microwd-channel, next to the old one, with its own service codes and API Key authentication.
  • Replacing the CredPay client in phiz-pay-card-vault with the new card contract.
  • A cutover driven by the route_cfg table, which operators already edit in the internal panel. Each operation switches path with one configuration row and switches back the same way, with no deploy.
  • Five phases, starting with PIX, the simplest flow, and leaving 3DS for last because it also changes the front end.

The RFC also lists what the new API does not cover: card terminals (TEF), statements for reconciliation, bank transfers and listings. Those operations stay on the old integration until CredPay answers the open questions.

8CredPay integrations today
4 → 1authentication methods
31current routes mapped
6operations with no equivalent

02Context: how it works today

CredPay handles cards (checkout, saved cards, pre-authorization, 3DS), PIX by QR Code and the merchants' card terminals. No app-facing service talks to it directly: the request goes down the service chain to the channel, which is the only service that knows CredPay, together with the card vault.

flowchart LR
  APP["phiz-flutter
app"] --> AS["microwd-appserver
app API"] AS --> BA["microwd-backapply
picks the route"] BA --> CH["microwd-channel
talks to providers"] CH --> CP[("CredPay
4 APIs")] CH --> CV["pay-card-vault
card vault"] CV --> CP IF["phiz-inner-front
panel"] --> IN["phiz-inner"] IN --> DB[("route_cfg
road_info")] DB -. "reads the route" .-> BA DB -. "reads the URL" .-> CH

Dashed lines are configuration reads. The panel is not part of the payment: it sets the rules before and shows the result after.

How an operation reaches CredPay

  1. backapply looks up route_cfg for the transaction type, payment method and card BIN (RoadRouteServiceImpl.getRouteByTranPayAcct). The route says which provider and which service code handle it.
  2. channel receives the code (for example B21, payment with a saved card) and runs the Spring service registered under that name.
  3. The service reads the provider base URL from road_info and calls CredPay.
Why this matters for the migration

Because the path is chosen by data, not by code, the new path can ship to production switched off and be turned on per merchant and per operation. Rolling back means changing the row again.

03Current integrations

Inventory taken from the code of phiz-microwd-channel and phiz-pay-card-vault.

#IntegrationWhereLoginService codes
1Checkout and saved cardsCheckOutTokenServiceImpl, CheckOutOperationServiceImpl, credPayRefactor/POST /AuthCredPayB20–B25, B02, B03, Z519, Z520, Z523
2Pre-authorizationPreAuthServicecheckout'sB26, B27, B28
3PIX, QR and bank transferservice/credpay/POST /oauth/tokenB10–B13
4Card with 3DSThreeDomainSecurePaymentServiceautenticacao/gerar-tokenB61–B70
5Card terminal (TEF)TefServicecheckout'sB47, B48
6ReconciliationSynChannelDataService, Credpay*ReconciliationJob/AuthCredPay/, hard-coded URLjobs
7Vault tokenizationcard-vault: CredpagamentosClientPOST /AuthCredPay—
8Card verificationcard-vault: CredpayClient/v1/autenticacao/gerar-token—
To confirm in Phase 0

The code shows what can be called. Which codes are live in production depends on route_cfg, which has not been queried yet. That inventory is the first implementation step.

04The new API

The documentation lives in the GruPag portal (login required) and has four parts: Access and API Key, PIX APIs, Card Purchase API and Simulation API.

flowchart LR
  subgraph HOJE["Today"]
    direction TB
    A1["/AuthCredPay
checkout · TEF · vault"] A2["/oauth/token
PIX"] A3["autenticacao/gerar-token
3DS"] A4["api-services /AuthCredPay
reconciliation"] end subgraph NOVO["GruPag API"] K["Authorization: Bearer gpk_…
Cliente-Id: company"] end HOJE ==> NOVO

Four logins, each with a token, cache and renewal, become one fixed key sent on every call.

General rules

TopicHow it works
Base URLhttps://api2-homolog.grupag.com.br (staging) and https://api2.grupag.com.br (production)
AuthenticationAPI Key gpk_… in Authorization: Bearer. One per portal user, no expiry and no renewal. Regenerating it invalidates the previous one immediately.
CompanyThe Cliente-Id header picks the linked company. Without it, the user's main company is used. It must be the same on every call of a flow.
AmountsCard: cents as a string ("15000"). PIX: reais as a decimal (15.00). Simulation: cents as an integer.
IdempotencyCard: by orderId; two concurrent calls return 409. PIX: the same amount within a short window returns 409.
ResponsesThe envelope varies by family (details, data or root fields). Errors always use {message}. 502: no destination. 504: provider did not answer.
HTTP
# Today: four different logins, each with its own token and renewal
POST {road_info.url}/AuthCredPay            # checkout, pre-auth, TEF, card-vault
POST {road_info.url}/oauth/token            # PIX and bank transfer
POST {road_info.url}autenticacao/gerar-token # 3DS (platform API)
POST https://api-services.credpay.com.br/AuthCredPay/   # reconciliation (hard-coded URL)
BASH
# New: one API Key (gpk_...) on every call, no login, no renewal
curl -X GET "https://api2-homolog.grupag.com.br/v1/pagamento/consulta/nit?nit=$NIT" \
  -H "Authorization: Bearer $GRUPAG_API_KEY" \
  -H "Cliente-Id: $CLIENTE_ID"   # same value on every call of the flow

05Goals and non-goals

Goals

  • Move card, saved card, 3DS, pre-authorization and PIX to the new API without losing any operation that is live today.
  • Replace the four logins and CredPayAuthTask with an API Key kept in the secrets vault.
  • Switch each operation on and off by configuration, per merchant, with no deploy.
  • Keep amount and status conversions in a single adapter.

Out of scope

  • Using the Simulation API to show installments and fees in the app. A possible improvement, not a migration requirement.
  • TEF, reconciliation and bank transfers, while the new API has no equivalent.
  • Other providers (Pinbank, Cronos, Afro).

06Route-by-route mapping

equivalent same operation, format changeschanges different rule or flownew did not existno equivalent stays on the old API

Saved card and checkout

TodayNew APIStatusWhat changes
POST /Tokenizacao/CriarToken
B20 · Z519
POST /v1/pagamento/cartao/adicionarchangesRequires authorizerId. A token works for one authorizer only: credit and debit need separate tokens. Store the customerId.
GET /Tokenizacao/Obter/{id}POST /v1/pagamento/cartao/buscarchangesReturns only the status (ATV or INA).
GET /Tokenizacao/Listar—no equivalentSee Gaps.
POST /Tokenizacao/Excluir/{id}
B24 · Z520
DELETE /v1/pagamento/cartao/removerequivalentDELETE with a {token, customer} body.
POST /Tokenizacao/Pagar
B21 · B02
POST /v1/pagamentochangesCents as a string; orderId required and idempotent; returns the nit, the new transaction key.
POST /Tokenizacao/Cancelar/{transacaoId}/{referenceId}
B25 · B03
DELETE /v1/pagamento/cancelarchanges{nit, amount} body, partial allowed. Refunds only until 23:59 on the capture day.
GET /Consulta/TransactionId/{id}
GET /Consulta/NumeroInterno/{n}
B22 · Z523
GET /v1/pagamento/consulta/nit?nit=changesBy nit only. No lookup by internal number or orderId.
GET /Consulta/Subdominio/Datas/{ini}/{fim}—no equivalentUsed for reconciliation.
JSON
{
  "nomeDoCliente": "JOAO DA SILVA",
  "documento": "12345678901",
  "quantidadeDeParcelas": 1,
  "valorInicial": 150.0,
  "token": "TOKEN_DO_CARTAO",
  "numeroInterno": "PED-4711",
  "subDominioId": 1234,
  "lojaId": 1
}
JSON
{
  "merchantChargeId": "20260901010707410895669",
  "orderId": "PED-4711",
  "installments": "1",
  "authorizerId": "2",
  "amount": "15000",
  "typeTransaction": "C",
  "card": {
    "token": "crd_d6dc9c299d15…"
  }
}

The same saved-card payment, before and after. The amount goes from reais to cents, and the internal number becomes orderId.

Pre-authorization

TodayNew APIStatusWhat changes
POST /Transacao/Autorizar
B26
POST /v1/pagamento/preautorizacaoequivalentSame body as payment; starts as AUTORIZADO.
POST /Transacao/Capturar/{transacaoId}/{referenceId}/{valor}
B27
POST /v1/pagamento/preautorizacao/liquidarequivalent{nit, amount} body; partial capture allowed.
POST /Transacao/Cancelar/{transacaoId}/{referenceId}
POST /Transacao/Cancelar/Parcial
B28
DELETE /v1/pagamento/cancelarequivalentOne endpoint; the amount decides whether it is partial. Voiding a hold has no time limit.

Card with 3DS

TodayNew APIStatusWhat changes
cartao/adicionar/
B62
POST /v1/pagamento/cartao/adicionarchangesSame as saved card.
cartao/validar/ · 3ds/checar/
B61 · B69
POST /v1/pagamento/cartao/buscarchangesConfirm whether "validar" does more than check the status today.
pagamento/cartao/3ds/configurar/
B63
POST /v1/pagamento/3ds/autenticacao
POST /v1/pagamento/3ds/configuracao
changesBecomes two calls. The first creates the merchantChargeId.
pagamento/cartao/3ds/desafio/
B64
browser stepschanges3DS Method and challenge are forms posted by the payer's browser. See section 07.
pagamento/cartao/3ds/checar/desafio/
B65
GET /v1/pagamento/3ds/consultar3DSequivalentApproved when eci and authentication.value are present.
pagamento/cartao/3ds/cobrar/
B66
POST /v1/pagamento + merchantChargeIdchangesThe authentication lasts 15 minutes and is consumed by the charge.
pagamento/cartao/3ds/preautorizada/cobrar/
B67
POST /v1/pagamento/preautorizacao (+ /liquidar)equivalent—
pagamento/cartao/3ds/cancelar/
B68
DELETE /v1/pagamento/cancelarchanges23:59 rule.
pagamento/cartao/3ds/consultar/GET /v1/pagamento/consulta/nitequivalent—

PIX

TodayNew APIStatusWhat changes
POST /api/generate-qrcodes
B10
POST /transacional/pix/qrcodeequivalentReais as a decimal. Synchronous, up to 30 s.
GET /api/find-qrcode/{id}
B11
GET /transacional/pix/consulta/{transactionId}equivalentPaid when the status is CONFIRMADO. No documented webhook.
POST /api/bank-transfers
B12
—no equivalent—
POST /api/list-transactions
B13
—no equivalent—
—POST /transacional/pix/cancelamento/{transactionId}newWithin 24 h it refunds immediately; after that it opens a dispute.
—POST /transacional/pix/disputanewAdmin profile only. Candidate for a panel screen.

Card vault

TodayNew APIStatusWhat changes
POST /Tokenizacao/CriarTokenPOST /v1/pagamento/cartao/adicionarchangesRequires authorizerId.
GET /Tokenizacao/ObterDadosToken/{token}POST /v1/pagamento/cartao/buscarchangesStatus only. Confirm whether the vault uses any other field of that response.
POST /Tokenizacao/Excluir/Token/{token}DELETE /v1/pagamento/cartao/removerequivalent—
POST /v1/pagamento (verification)POST /v1/pagamentoequivalentSame path; base URL and authentication change, and orderId becomes required.

07New card flow with 3DS

The biggest flow change is in 3DS. Today backapply returns a ready-made URL (certifyUrl, in CardCertifyServiceImpl) and the front end just opens it. With the new API, two steps run in the payer's browser, and the front end has to build and post the forms.

sequenceDiagram
  autonumber
  participant F as Payer front end
  participant BA as backapply
  participant CH as channel
  participant G as GruPag API
  participant E as Issuing bank
  BA->>CH: start 3DS for the order
  CH->>G: POST /3ds/autenticacao
  G-->>CH: merchantChargeId and threeDsMethod
  CH-->>BA: 3DS Method data
  BA-->>F: data for the browser
  F->>E: 3DS Method in a hidden iframe
  BA->>CH: authenticate with browser data
  CH->>G: POST /3ds/configuracao
  G-->>CH: frictionless or challenge
  F->>E: challenge with creq, if any
  CH->>G: GET /3ds/consultar3DS
  G-->>CH: eci and CAVV
  CH->>G: POST /v1/pagamento with merchantChargeId
  G-->>CH: nit and status CONFIRMADO

The same Cliente-Id must go on every call to the GruPag API in this flow. If one call misses it, the payment answers "3DS not found".

Front-end impact

We still need to identify which front end opens the certifyUrl today (the app or a web form). It has to collect real browser data (screen, time zone, user agent), post the 3DS Method in a hidden iframe and show the challenge in a 400×650 iframe.

08New PIX flow

PIX barely changes shape: generate, then poll until paid. What is new is the refund with a time rule, and disputes.

sequenceDiagram
  autonumber
  participant CH as channel
  participant G as GruPag API
  participant P as Payer
  CH->>G: POST /transacional/pix/qrcode
  G-->>CH: transactionId and copy-and-paste code
  CH-->>P: QR Code
  P->>G: pays at the bank
  loop until CONFIRMADO or EXPIRADO
    CH->>G: GET /transacional/pix/consulta/{id}
    G-->>CH: status
  end
stateDiagram-v2
  [*] --> GERADO
  GERADO --> CONFIRMADO: payment
  GERADO --> EXPIRADO: expired
  CONFIRMADO --> ESTORNANDO: refund within 24 h
  ESTORNANDO --> ESTORNADO
  CONFIRMADO --> DISPUTA: refund after 24 h
  DISPUTA --> CANCELANDO: admin approves
  CANCELANDO --> CANCELADO
  DISPUTA --> PAGO: admin denies

Status of a PIX charge in the new API. Disputes are decided by an Admin user, which calls for a screen in the internal panel.

BASH
curl -X POST "https://api2-homolog.grupag.com.br/transacional/pix/qrcode" \
  -H "Authorization: Bearer $GRUPAG_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "amount": 15.00, "description": "Pedido PED-12345", "expirationSeconds": 3600 }'
# 200 → { "transactionId": "a1b2…", "status": "GERADO", "pixCopyAndPaste": "000201…", "destination": "TRANSACIONAL-PIX-SICREDI" }

09Gaps

These operations are not in the new documentation. They stay on the current integration until CredPay names a replacement.

OperationUsed today forImpact if switched off
TEF terminal: /Pdv/CriarOperacao, /Pdv/GetOperacaoIn-person sales (B47, B48)CredPay POS sales stop.
Statement: /Movimentacao/Analitico, /Consulta/Subdominio/DatasDaily reconciliationReconciliation can no longer check this provider.
Bank transfer: /api/bank-transfersB12Transfers through this provider stop.
Listings: /Tokenizacao/Listar, /api/list-transactionsLookup and syncWe rely only on our own records.
Recurring paymentsRecurrence fields in CheckOutPayReqThe docs mention a recurrence contract but not its routes.
Webhooks—Confirmation by polling only.

10Breaking changes

ChangeTodayNew APIWhat to do
Card tokensCreated in /Tokenizacao/CriarTokenUnclear whether they work in /v1/pagamentoConfirm with CredPay. If not, re-tokenize through the vault before Phase 2.
AmountsReais as BigDecimal (valorInicial)Card in cents (string); PIX in reaisConvert in a single place in the adapter.
IdentifierstransacaoId, referenceId, numeroInternonit, merchantChargeId, customerIdNew columns on orders and cards.
Refund windowNo documented limitCard: until 23:59 that day. PIX: after 24 h it becomes a dispute.Handle in the app and panel; a routine for refunds outside the API.
CompanysubDominioId, lojaIdCliente-Id headerMap each merchant; resolve once per order and reuse.
3DSReady-made URLBrowser formsChange the front end.
StatusCheckout labelsCONFIRMADO, AUTORIZADO, PENDENTE, NEGADO…Conversion table in the adapter.
JAVA
// Single conversion point in the channel's GruPag adapter
static String toCents(BigDecimal reais) {           // card: cents as a string
    return reais.setScale(2, RoundingMode.UNNECESSARY).movePointRight(2).toPlainString();
}
static BigDecimal toPixReais(BigDecimal reais) {      // PIX: reais as a decimal
    return reais.setScale(2, RoundingMode.UNNECESSARY);
}

11Technical proposal

A new provider, next to the old one

Instead of changing the current services, the channel gets a new adapter (service/grupag/) with its own service codes and a road_info entry pointing to api2.grupag.com.br. Both paths coexist; the route decides which one is used.

flowchart LR
  BA["backapply"] --> RC{"route_cfg
per merchant
and operation"} RC -- "old code" --> OLD["Current CredPay services
B10 · B21 · B61 …"] RC -- "new code" --> NEW["GruPag adapter
new codes"] OLD --> CP[("Current CredPay APIs")] NEW --> GP[("api2.grupag.com.br")] OP["Operator in the panel"] -. "edits the row
to switch or roll back" .-> RC

Switching an operation means editing route_cfg in the panel. Rolling back means undoing the edit.

Changes per repository

RepositoryChange
phiz-microwd-channelHTTP client with API Key and Cliente-Id; card, 3DS, pre-authorization and PIX adapters; amount and status conversion; registration of the new codes.
phiz-pay-card-vaultReplace CredpagamentosClient and CredpayClient with the new contract, behind configuration.
phiz-microwd-backapplyStore nit, merchantChargeId and customerId; adapt CardCertifyServiceImpl to the new 3DS; handle the refund window.
phiz-microwd-commonNew columns on the order and card entities.
phiz-inner and phiz-inner-frontRegister the codes and the road_info entry; PIX dispute screen.
3DS front end3DS Method and challenge in the browser.
Credential

The API Key does not expire, but regenerating it kills the previous one without notice. It lives in each environment's secrets vault, never in code or in plain text in road_info, and is rotated in an agreed window.

BASH
# Full or partial refund (card). Only until 23:59 on the capture day (Brasília time).
curl -X DELETE "https://api2-homolog.grupag.com.br/v1/pagamento/cancelar" \
  -H "Authorization: Bearer $GRUPAG_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "nit": "pag_59c416ca3552…", "amount": "5000" }'

12Migration plan

PHASE 0
Preparation
  • Inventory live CredPay codes in route_cfg
  • Staging key
  • CredPay's answers, especially on tokens
PHASE 1
PIX
  • Generate QR and poll
  • One test merchant
  • Refund and dispute
PHASE 2
Card without 3DS
  • Tokenization, payment, cancellation, lookup
  • Card vault
  • Re-tokenization, if needed
PHASE 3
3DS
  • New flow in the channel
  • Front-end change
PHASE 4
Pre-authorization
  • Hold, capture, void
PHASE 5
Decommission
  • Remove old codes
  • Remove CredPayAuthTask and old clients
  • TEF and reconciliation stay until there is a replacement

In every phase

  1. Contract tests in staging, using CredPay's Postman collection as the reference.
  2. One pilot merchant in production, switched by route.
  3. Watch approval rate, 4xx/5xx errors per code and response time, compared with the old path.
  4. Switch the remaining merchants in batches.

Dates will be set after Phase 0, once we know what is live and what CredPay has answered.

13Risks

RiskMitigation
Old tokens do not work in the new APIConfirm in Phase 0; if so, re-tokenize through the vault before Phase 2.
Cliente-Id changes mid-flowResolve once per order, store and reuse; automated test of the full 3DS flow.
Unit mix-up (reais vs cents)One conversion point, with contract tests per endpoint.
Refund rejected after 23:59Warn in the app and panel; a routine for refunds outside the API.
Reconciliation with no data sourceKeep the old statement until there is a replacement.
Staging pointing at productionThe card vault defaults to the production base today because the sandbox was broken. With the new API, require the staging base outside production.

14Open questions for CredPay

  1. Tokens. Do tokens created in /Tokenizacao/CriarToken and in the vault work in /v1/pagamento? Is there a bulk migration?
  2. Gaps. What replaces TEF, statements, bank transfers and transaction listings?
  3. Webhooks. Is there a confirmation notification for PIX and card, or only polling?
  4. Recurring. What are the routes of the recurrence contract mentioned in the docs?
  5. Simulation. Is hashSimulacao checked on payment? The simulation page says yes; the card page says it is accepted and ignored.
  6. Companies. How should our merchants map to Cliente-Id: one key per environment with all of them linked, or one key per merchant?
  7. Limits. Is there a rate limit per key?
  8. Timeline. When will the current APIs be switched off?

15References

  • GruPag documentation (login required): Access and API Key, PIX APIs, Card Purchase API, Simulation API.
  • channel: CheckOutTokenServiceImpl, CheckOutOperationServiceImpl, PreAuthService, service/credpay/impl/*, ThreeDomainSecurePaymentService, TefService, SynChannelDataService, ApiCodeConstant.
  • card-vault: CredpagamentosClient, CredpayClient, application.yaml.
  • backapply: RoadRouteServiceImpl, CardCertifyServiceImpl.
RFC PHZ-0002 · 评审草案

将 CredPay 集成迁移到 GruPag API

把目前分散在四套 API、各自登录方式不同的 CredPay 路由,替换为新的 GruPag API:一个基础地址、一个 API Key、金额以分为单位,银行卡、3DS、预授权和 PIX 使用统一的接口规范。切换按操作逐项进行,通过内部管理后台的路由配置控制;每项操作验证通过之前,旧路径保持开启。

状态
草案
作者
Gleison(PHIZ 工程团队)
日期
2026-10-16
评审人
Pedro Bettani(巴西)
Luciana Geromel(巴西)
Richard Liang(中国)
Henry Wu(中国)
涉及系统
channel · card-vault · backapply

01摘要

CredPay 发布了新的 API,文档位于 GruPag 门户(api2.grupag.com.br)。目前我们通过两个服务中的八个集成对接 CredPay,使用四种不同的登录方式。本 RFC 提议:

  • 在 phiz-microwd-channel 中新增一个适配器,与旧适配器并存,使用独立的服务编码,并通过 API Key 认证。
  • 将 phiz-pay-card-vault 中的 CredPay 客户端替换为新的银行卡接口。
  • 通过 route_cfg 表控制切换。运营人员已经在内部管理后台维护这张表。每项操作改一行配置即可切换,改回即可回滚,无需发版。
  • 分五个阶段:先做最简单的 PIX,最后做 3DS,因为 3DS 还涉及前端改动。

本 RFC 也列出了新 API 尚未覆盖的能力:刷卡终端(TEF)、对账用的流水、银行转账和列表查询。这些操作在 CredPay 回答待定问题之前继续使用旧集成。

8当前 CredPay 集成
4 → 1认证方式
31已映射的现有路由
6无对应的操作

02背景:当前的工作方式

CredPay 负责银行卡(收银台、已保存的卡、预授权、3DS)、PIX 二维码收款以及商户的刷卡终端。面向 App 的服务都不直接调用它:请求沿服务链传到 channel,只有 channel 和卡片保险库(card-vault)对接 CredPay。

flowchart LR
  APP["phiz-flutter
App"] --> AS["microwd-appserver
App 接口"] AS --> BA["microwd-backapply
选择路由"] BA --> CH["microwd-channel
对接渠道"] CH --> CP[("CredPay
4 套 API")] CH --> CV["pay-card-vault
卡片保险库"] CV --> CP IF["phiz-inner-front
管理后台"] --> IN["phiz-inner"] IN --> DB[("route_cfg
road_info")] DB -. "读取路由" .-> BA DB -. "读取地址" .-> CH

虚线表示读取配置。管理后台不参与支付本身:它在支付之前设定规则,在支付之后展示结果。

一次操作如何到达 CredPay

  1. backapply 按交易类型、支付方式和卡 BIN 在 route_cfg 中查找路由(RoadRouteServiceImpl.getRouteByTranPayAcct)。路由决定由哪个渠道、哪个服务编码处理。
  2. channel 收到编码(例如 B21,已保存卡支付),执行以该名称注册的 Spring 服务。
  3. 该服务从 road_info 读取渠道基础地址,然后调用 CredPay。
这对迁移意味着什么

路径由数据而不是代码决定,所以新路径可以先以关闭状态上线,再按商户、按操作打开。回滚只需把这一行改回去。

03现有集成

以下清单来自 phiz-microwd-channel 和 phiz-pay-card-vault 的代码。

#集成位置登录服务编码
1收银台与已保存的卡CheckOutTokenServiceImpl、CheckOutOperationServiceImpl、credPayRefactor/POST /AuthCredPayB20–B25、B02、B03、Z519、Z520、Z523
2预授权PreAuthService同收银台B26、B27、B28
3PIX、二维码与银行转账service/credpay/POST /oauth/tokenB10–B13
43DS 银行卡ThreeDomainSecurePaymentServiceautenticacao/gerar-tokenB61–B70
5刷卡终端(TEF)TefService同收银台B47、B48
6对账SynChannelDataService、Credpay*ReconciliationJob/AuthCredPay/,地址写死在代码中定时任务
7保险库令牌化card-vault:CredpagamentosClientPOST /AuthCredPay—
8卡片验证card-vault:CredpayClient/v1/autenticacao/gerar-token—
在第 0 阶段确认

代码只说明哪些接口可以被调用。生产环境实际启用了哪些编码取决于 route_cfg,目前还没有查询。这份清单是实施的第一步。

04新 API

文档位于 GruPag 门户(需要登录),共四部分:访问与 API Key、PIX API、银行卡支付 API、费率模拟 API。

flowchart LR
  subgraph HOJE["现在"]
    direction TB
    A1["/AuthCredPay
收银台 · TEF · 保险库"] A2["/oauth/token
PIX"] A3["autenticacao/gerar-token
3DS"] A4["api-services /AuthCredPay
对账"] end subgraph NOVO["GruPag API"] K["Authorization: Bearer gpk_…
Cliente-Id: 公司"] end HOJE ==> NOVO

四种各自带令牌、缓存和续期的登录方式,变成每次调用都携带的一个固定密钥。

通用规则

主题说明
基础地址https://api2-homolog.grupag.com.br(测试)和 https://api2.grupag.com.br(生产)
认证在 Authorization: Bearer 中携带 API Key gpk_…。每个门户用户一个,永不过期,也无需续期。重新生成会立即使旧密钥失效。
公司请求头 Cliente-Id 选择关联的公司。不传则使用用户的主公司。同一流程中的每次调用都必须一致。
金额银行卡:以分为单位的字符串("15000")。PIX:以雷亚尔为单位的小数(15.00)。模拟:以分为单位的整数。
幂等银行卡:按 orderId;并发的两次调用返回 409。PIX:短时间内相同金额返回 409。
响应不同接口族的外层结构不同(details、data 或字段在根级)。错误统一为 {message}。502:无法确定目标渠道。504:渠道未响应。
HTTP
# Today: four different logins, each with its own token and renewal
POST {road_info.url}/AuthCredPay            # checkout, pre-auth, TEF, card-vault
POST {road_info.url}/oauth/token            # PIX and bank transfer
POST {road_info.url}autenticacao/gerar-token # 3DS (platform API)
POST https://api-services.credpay.com.br/AuthCredPay/   # reconciliation (hard-coded URL)
BASH
# New: one API Key (gpk_...) on every call, no login, no renewal
curl -X GET "https://api2-homolog.grupag.com.br/v1/pagamento/consulta/nit?nit=$NIT" \
  -H "Authorization: Bearer $GRUPAG_API_KEY" \
  -H "Cliente-Id: $CLIENTE_ID"   # same value on every call of the flow

05目标与非目标

目标

  • 将银行卡、已保存的卡、3DS、预授权和 PIX 迁移到新 API,不丢失任何当前在用的操作。
  • 用存放在密钥库中的 API Key 取代四种登录方式和 CredPayAuthTask。
  • 按商户、通过配置开启或关闭每项操作,无需发版。
  • 金额和状态的转换集中在一个适配器中。

不在范围内

  • 使用费率模拟 API 在 App 中展示分期和费率。这是可选的改进,不是迁移的前提。
  • 新 API 尚无对应能力的 TEF、对账和银行转账。
  • 其他渠道(Pinbank、Cronos、Afro)。

06逐条路由映射

对应 同一操作,仅格式调整变化 规则或流程不同新增 以前没有无对应 保留旧接口

已保存的卡与收银台

现在新 API状态变化
POST /Tokenizacao/CriarToken
B20 · Z519
POST /v1/pagamento/cartao/adicionar变化需要 authorizerId。一个令牌只对应一个授权方:信用和借记需要分别令牌化。需保存返回的 customerId。
GET /Tokenizacao/Obter/{id}POST /v1/pagamento/cartao/buscar变化只返回状态(ATV 或 INA)。
GET /Tokenizacao/Listar—无对应见缺口。
POST /Tokenizacao/Excluir/{id}
B24 · Z520
DELETE /v1/pagamento/cartao/remover对应带请求体 {token, customer} 的 DELETE。
POST /Tokenizacao/Pagar
B21 · B02
POST /v1/pagamento变化金额为分(字符串);orderId 必填且幂等;返回 nit,作为新的交易主键。
POST /Tokenizacao/Cancelar/{transacaoId}/{referenceId}
B25 · B03
DELETE /v1/pagamento/cancelar变化请求体 {nit, amount},支持部分退款。只能在扣款当天 23:59 之前退款。
GET /Consulta/TransactionId/{id}
GET /Consulta/NumeroInterno/{n}
B22 · Z523
GET /v1/pagamento/consulta/nit?nit=变化只能按 nit 查询,不支持按内部编号或 orderId 查询。
GET /Consulta/Subdominio/Datas/{ini}/{fim}—无对应用于对账。
JSON
{
  "nomeDoCliente": "JOAO DA SILVA",
  "documento": "12345678901",
  "quantidadeDeParcelas": 1,
  "valorInicial": 150.0,
  "token": "TOKEN_DO_CARTAO",
  "numeroInterno": "PED-4711",
  "subDominioId": 1234,
  "lojaId": 1
}
JSON
{
  "merchantChargeId": "20260901010707410895669",
  "orderId": "PED-4711",
  "installments": "1",
  "authorizerId": "2",
  "amount": "15000",
  "typeTransaction": "C",
  "card": {
    "token": "crd_d6dc9c299d15…"
  }
}

同一笔已保存卡支付的前后对比。金额从雷亚尔改为分,内部编号改为 orderId。

预授权

现在新 API状态变化
POST /Transacao/Autorizar
B26
POST /v1/pagamento/preautorizacao对应请求体与支付相同;初始状态为 AUTORIZADO。
POST /Transacao/Capturar/{transacaoId}/{referenceId}/{valor}
B27
POST /v1/pagamento/preautorizacao/liquidar对应请求体 {nit, amount};支持部分请款。
POST /Transacao/Cancelar/{transacaoId}/{referenceId}
POST /Transacao/Cancelar/Parcial
B28
DELETE /v1/pagamento/cancelar对应合并为一个接口,由金额决定是否部分撤销。撤销预授权没有时间限制。

3DS 银行卡

现在新 API状态变化
cartao/adicionar/
B62
POST /v1/pagamento/cartao/adicionar变化同已保存的卡。
cartao/validar/ · 3ds/checar/
B61 · B69
POST /v1/pagamento/cartao/buscar变化需确认现在的 "validar" 是否不止检查状态。
pagamento/cartao/3ds/configurar/
B63
POST /v1/pagamento/3ds/autenticacao
POST /v1/pagamento/3ds/configuracao
变化拆成两次调用。第一次生成 merchantChargeId。
pagamento/cartao/3ds/desafio/
B64
浏览器端步骤变化3DS Method 和挑战由付款人的浏览器提交表单完成。见第 07 节。
pagamento/cartao/3ds/checar/desafio/
B65
GET /v1/pagamento/3ds/consultar3DS对应返回 eci 和 authentication.value 即为通过。
pagamento/cartao/3ds/cobrar/
B66
POST /v1/pagamento + merchantChargeId变化认证有效期 15 分钟,扣款时被消耗。
pagamento/cartao/3ds/preautorizada/cobrar/
B67
POST /v1/pagamento/preautorizacao(+ /liquidar)对应—
pagamento/cartao/3ds/cancelar/
B68
DELETE /v1/pagamento/cancelar变化23:59 规则。
pagamento/cartao/3ds/consultar/GET /v1/pagamento/consulta/nit对应—

PIX

现在新 API状态变化
POST /api/generate-qrcodes
B10
POST /transacional/pix/qrcode对应金额为雷亚尔小数。同步调用,最长 30 秒。
GET /api/find-qrcode/{id}
B11
GET /transacional/pix/consulta/{transactionId}对应状态为 CONFIRMADO 即已支付。文档中没有 Webhook。
POST /api/bank-transfers
B12
—无对应—
POST /api/list-transactions
B13
—无对应—
—POST /transacional/pix/cancelamento/{transactionId}新增24 小时内立即退款;超过 24 小时进入争议。
—POST /transacional/pix/disputa新增仅限 Admin 角色。可考虑在管理后台增加页面。

卡片保险库

现在新 API状态变化
POST /Tokenizacao/CriarTokenPOST /v1/pagamento/cartao/adicionar变化需要 authorizerId。
GET /Tokenizacao/ObterDadosToken/{token}POST /v1/pagamento/cartao/buscar变化只返回状态。需确认保险库是否用到该响应中的其他字段。
POST /Tokenizacao/Excluir/Token/{token}DELETE /v1/pagamento/cartao/remover对应—
POST /v1/pagamento(卡片验证)POST /v1/pagamento对应路径相同;基础地址和认证变化,并且 orderId 变为必填。

07新的 3DS 银行卡流程

流程上最大的变化在 3DS。现在 backapply 返回一个现成的地址(CardCertifyServiceImpl 中的 certifyUrl),前端只需打开。新 API 中有两个步骤在付款人的浏览器中执行,前端需要自己构造并提交表单。

sequenceDiagram
  autonumber
  participant F as 付款人前端
  participant BA as backapply
  participant CH as channel
  participant G as GruPag API
  participant E as 发卡行
  BA->>CH: 为订单发起 3DS
  CH->>G: POST /3ds/autenticacao
  G-->>CH: merchantChargeId 和 threeDsMethod
  CH-->>BA: 3DS Method 数据
  BA-->>F: 交给浏览器的数据
  F->>E: 在隐藏 iframe 中执行 3DS Method
  BA->>CH: 携带浏览器数据进行认证
  CH->>G: POST /3ds/configuracao
  G-->>CH: 无感通过或需要挑战
  F->>E: 如有挑战,提交 creq
  CH->>G: GET /3ds/consultar3DS
  G-->>CH: eci 和 CAVV
  CH->>G: POST /v1/pagamento 携带 merchantChargeId
  G-->>CH: nit 和状态 CONFIRMADO

此流程中对 GruPag API 的每次调用都必须携带相同的 Cliente-Id。只要有一次缺失,支付就会返回"3DS 未找到"。

对前端的影响

还需要确认目前是哪个前端打开 certifyUrl(App 还是网页表单)。它需要采集真实的浏览器数据(屏幕、时区、User-Agent),在隐藏 iframe 中提交 3DS Method,并在 400×650 的 iframe 中展示挑战页面。

08新的 PIX 流程

PIX 的流程形态基本不变:生成二维码,然后轮询直到支付完成。新增的是带时限规则的退款,以及争议处理。

sequenceDiagram
  autonumber
  participant CH as channel
  participant G as GruPag API
  participant P as 付款人
  CH->>G: POST /transacional/pix/qrcode
  G-->>CH: transactionId 和复制粘贴码
  CH-->>P: 二维码
  P->>G: 在银行完成付款
  loop 直到 CONFIRMADO 或 EXPIRADO
    CH->>G: GET /transacional/pix/consulta/{id}
    G-->>CH: 状态
  end
stateDiagram-v2
  [*] --> GERADO
  GERADO --> CONFIRMADO: 付款
  GERADO --> EXPIRADO: 过期
  CONFIRMADO --> ESTORNANDO: 24 小时内退款
  ESTORNANDO --> ESTORNADO
  CONFIRMADO --> DISPUTA: 超过 24 小时退款
  DISPUTA --> CANCELANDO: 管理员批准
  CANCELANDO --> CANCELADO
  DISPUTA --> PAGO: 管理员驳回

新 API 中一笔 PIX 收款的状态。争议由 Admin 用户裁决,因此需要在内部管理后台提供页面。

BASH
curl -X POST "https://api2-homolog.grupag.com.br/transacional/pix/qrcode" \
  -H "Authorization: Bearer $GRUPAG_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "amount": 15.00, "description": "Pedido PED-12345", "expirationSeconds": 3600 }'
# 200 → { "transactionId": "a1b2…", "status": "GERADO", "pixCopyAndPaste": "000201…", "destination": "TRANSACIONAL-PIX-SICREDI" }

09缺口

以下操作在新文档中没有出现。在 CredPay 给出替代方案之前,继续使用现有集成。

操作当前用途关闭后的影响
TEF 终端:/Pdv/CriarOperacao、/Pdv/GetOperacao线下刷卡(B47、B48)CredPay POS 收款停止。
流水:/Movimentacao/Analitico、/Consulta/Subdominio/Datas每日对账对账无法再核对该渠道。
银行转账:/api/bank-transfersB12经该渠道的转账停止。
列表:/Tokenizacao/Listar、/api/list-transactions查询与同步只能依赖我们自己的记录。
周期扣款CheckOutPayReq 中的周期扣款字段文档提到周期扣款合约,但没有给出路由。
Webhook—只能通过轮询确认结果。

10不兼容变更

变更现在新 API处理方式
卡令牌在 /Tokenizacao/CriarToken 中创建不确定能否在 /v1/pagamento 中使用向 CredPay 确认。如不能,在第 2 阶段前通过保险库重新令牌化。
金额雷亚尔,BigDecimal(valorInicial)银行卡为分(字符串);PIX 为雷亚尔在适配器中集中一处转换。
标识transacaoId、referenceId、numeroInternonit、merchantChargeId、customerId在订单和卡片表中新增字段。
退款时限文档无明确限制银行卡:当天 23:59 前。PIX:超过 24 小时进入争议。在 App 和管理后台中处理;提供 API 之外的退款流程。
公司subDominioId、lojaId请求头 Cliente-Id为每个商户建立映射;每个订单只解析一次并复用。
3DS现成地址浏览器表单修改前端。
状态收银台的状态值CONFIRMADO、AUTORIZADO、PENDENTE、NEGADO…在适配器中维护转换表。
JAVA
// Single conversion point in the channel's GruPag adapter
static String toCents(BigDecimal reais) {           // card: cents as a string
    return reais.setScale(2, RoundingMode.UNNECESSARY).movePointRight(2).toPlainString();
}
static BigDecimal toPixReais(BigDecimal reais) {      // PIX: reais as a decimal
    return reais.setScale(2, RoundingMode.UNNECESSARY);
}

11技术方案

新渠道与旧渠道并存

不改动现有服务,而是在 channel 中新增适配器(service/grupag/),使用独立的服务编码,并新增一条指向 api2.grupag.com.br 的 road_info。两条路径并存,由路由决定走哪一条。

flowchart LR
  BA["backapply"] --> RC{"route_cfg
按商户
按操作"} RC -- "旧编码" --> OLD["现有 CredPay 服务
B10 · B21 · B61 …"] RC -- "新编码" --> NEW["GruPag 适配器
新编码"] OLD --> CP[("现有 CredPay API")] NEW --> GP[("api2.grupag.com.br")] OP["管理后台的运营人员"] -. "修改该行
切换或回滚" .-> RC

切换一项操作就是在管理后台修改 route_cfg,回滚就是撤销这次修改。

各仓库的改动

仓库改动
phiz-microwd-channel携带 API Key 和 Cliente-Id 的 HTTP 客户端;银行卡、3DS、预授权和 PIX 适配器;金额与状态转换;注册新编码。
phiz-pay-card-vault用新接口替换 CredpagamentosClient 和 CredpayClient,通过配置开关控制。
phiz-microwd-backapply保存 nit、merchantChargeId 和 customerId;让 CardCertifyServiceImpl 适配新的 3DS;处理退款时限。
phiz-microwd-common在订单和卡片实体中新增字段。
phiz-inner 和 phiz-inner-front登记新编码和 road_info;PIX 争议页面。
3DS 前端在浏览器中执行 3DS Method 和挑战。
凭证

API Key 不会过期,但重新生成会在没有提示的情况下使旧密钥失效。它存放在各环境的密钥库中,不写入代码,也不以明文存入 road_info,并在约定的窗口期内更换。

BASH
# Full or partial refund (card). Only until 23:59 on the capture day (Brasília time).
curl -X DELETE "https://api2-homolog.grupag.com.br/v1/pagamento/cancelar" \
  -H "Authorization: Bearer $GRUPAG_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "nit": "pag_59c416ca3552…", "amount": "5000" }'

12迁移计划

第 0 阶段
准备
  • 在 route_cfg 中盘点在用的 CredPay 编码
  • 测试环境密钥
  • CredPay 的答复,尤其是令牌问题
第 1 阶段
PIX
  • 生成二维码与轮询
  • 一个测试商户
  • 退款与争议
第 2 阶段
无 3DS 银行卡
  • 令牌化、支付、取消、查询
  • 卡片保险库
  • 必要时重新令牌化
第 3 阶段
3DS
  • channel 中的新流程
  • 前端改动
第 4 阶段
预授权
  • 冻结、请款、撤销
第 5 阶段
下线
  • 移除旧编码
  • 移除 CredPayAuthTask 和旧客户端
  • TEF 和对账在有替代方案前保留

每个阶段

  1. 在测试环境做接口契约测试,以 CredPay 的 Postman 集合为参考。
  2. 在生产环境选一个试点商户,通过路由切换。
  3. 与旧路径对比,观察授权成功率、各编码的 4xx/5xx 错误和响应时间。
  4. 分批切换其余商户。

具体日期在第 0 阶段之后确定,届时我们会知道哪些编码在用以及 CredPay 的答复。

13风险

风险应对
旧令牌在新 API 中不可用在第 0 阶段确认;如不可用,在第 2 阶段前通过保险库重新令牌化。
流程中途 Cliente-Id 不一致每个订单只解析一次,保存并复用;对完整 3DS 流程做自动化测试。
金额单位错误(雷亚尔与分)只在一处转换,并按接口做契约测试。
23:59 之后退款被拒在 App 和管理后台中提示;提供 API 之外的退款流程。
对账缺少数据来源在有替代方案前保留旧的流水接口。
测试环境指向生产card-vault 目前默认使用生产地址,因为当时测试环境不可用。新 API 在非生产环境必须使用测试地址。

14需要 CredPay 回答的问题

  1. 令牌。在 /Tokenizacao/CriarToken 和保险库中创建的令牌能否在 /v1/pagamento 中使用?是否支持批量迁移?
  2. 缺口。TEF、流水、银行转账和交易列表的替代方案是什么?
  3. Webhook。PIX 和银行卡是否有结果通知,还是只能轮询?
  4. 周期扣款。文档中提到的周期扣款合约有哪些路由?
  5. 模拟。支付时是否校验 hashSimulacao?模拟页面说会校验,银行卡页面说会接收但忽略。
  6. 公司。我们的商户如何对应到 Cliente-Id:每个环境一个密钥并关联所有商户,还是每个商户一个密钥?
  7. 限流。每个密钥是否有请求频率限制?
  8. 时间表。现有 API 何时下线?

15参考资料

  • GruPag 文档(需要登录):访问与 API Key、PIX API、银行卡支付 API、费率模拟 API。
  • channel:CheckOutTokenServiceImpl、CheckOutOperationServiceImpl、PreAuthService、service/credpay/impl/*、ThreeDomainSecurePaymentService、TefService、SynChannelDataService、ApiCodeConstant。
  • card-vault:CredpagamentosClient、CredpayClient、application.yaml。
  • backapply:RoadRouteServiceImpl、CardCertifyServiceImpl。