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.
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-vaultpelo 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.
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
- O backapply procura em
route_cfga 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. - O channel recebe o código (por exemplo
B21, pagamento com cartão salvo) e executa o serviço Spring registrado com esse nome. - O serviço busca a URL base do canal em
road_infoe chama a CredPay.
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ção | Onde está | Login | Códigos de serviço |
|---|---|---|---|---|
| 1 | Checkout e cartão salvo | CheckOutTokenServiceImpl, CheckOutOperationServiceImpl, credPayRefactor/ | POST /AuthCredPay | B20–B25, B02, B03, Z519, Z520, Z523 |
| 2 | Pré-autorização | PreAuthService | o do checkout | B26, B27, B28 |
| 3 | PIX, QR e transferência | service/credpay/ | POST /oauth/token | B10–B13 |
| 4 | Cartão com 3DS | ThreeDomainSecurePaymentService | autenticacao/gerar-token | B61–B70 |
| 5 | Maquininha (TEF) | TefService | o do checkout | B47, B48 |
| 6 | Conciliação | SynChannelDataService, Credpay*ReconciliationJob | /AuthCredPay/, URL fixa | jobs |
| 7 | Tokenização do cofre | card-vault: CredpagamentosClient | POST /AuthCredPay | — |
| 8 | Validação de cartão | card-vault: CredpayClient | /v1/autenticacao/gerar-token | — |
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
| Tema | Como funciona |
|---|---|
| Base | https://api2-homolog.grupag.com.br (homologação) e https://api2.grupag.com.br (produção) |
| Autenticação | API Key gpk_… no header Authorization: Bearer. Uma por usuário do portal, sem validade e sem renovação. Regenerar invalida a anterior na hora. |
| Empresa | Header Cliente-Id escolhe a empresa vinculada. Sem ele, vale a empresa principal. Precisa ser igual em todas as chamadas do fluxo. |
| Valores | Cartão: centavos em string ("15000"). PIX: reais em decimal (15.00). Simulação: centavos em inteiro. |
| Idempotência | Cartão: pelo orderId, e duas chamadas simultâneas dão 409. PIX: mesmo valor numa janela curta dá 409. |
| Respostas | O envelope muda por família (details, data ou campos na raiz). Erro sempre com {message}. 502: sem destino. 504: provedor não respondeu. |
# 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)# 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 flow05Objetivos 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
CredPayAuthTaskpor 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
Cartão salvo e checkout
| Hoje | API nova | Situação | O que muda |
|---|---|---|---|
| POST /Tokenizacao/CriarToken B20 · Z519 | POST /v1/pagamento/cartao/adicionar | muda | Exige 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/buscar | muda | Devolve só o status (ATV ou INA). |
| GET /Tokenizacao/Listar | — | sem equivalente | Ver Lacunas. |
| POST /Tokenizacao/Excluir/{id} B24 · Z520 | DELETE /v1/pagamento/cartao/remover | equivalente | DELETE com corpo {token, customer}. |
| POST /Tokenizacao/Pagar B21 · B02 | POST /v1/pagamento | muda | Centavos 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/cancelar | muda | Corpo {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= | muda | Só por nit. Não há busca por número interno nem por orderId. |
| GET /Consulta/Subdominio/Datas/{ini}/{fim} | — | sem equivalente | Usado na conciliação. |
{
"nomeDoCliente": "JOAO DA SILVA",
"documento": "12345678901",
"quantidadeDeParcelas": 1,
"valorInicial": 150.0,
"token": "TOKEN_DO_CARTAO",
"numeroInterno": "PED-4711",
"subDominioId": 1234,
"lojaId": 1
}{
"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
| Hoje | API nova | Situação | O que muda |
|---|---|---|---|
| POST /Transacao/Autorizar B26 | POST /v1/pagamento/preautorizacao | equivalente | Mesmo corpo do pagamento; nasce AUTORIZADO. |
| POST /Transacao/Capturar/{transacaoId}/{referenceId}/{valor} B27 | POST /v1/pagamento/preautorizacao/liquidar | equivalente | Corpo {nit, amount}; aceita captura parcial. |
| POST /Transacao/Cancelar/{transacaoId}/{referenceId} POST /Transacao/Cancelar/Parcial B28 | DELETE /v1/pagamento/cancelar | equivalente | Um endpoint; o valor define se é parcial. Desfazer reserva não tem limite de horário. |
Cartão com 3DS
| Hoje | API nova | Situação | O que muda |
|---|---|---|---|
| cartao/adicionar/ B62 | POST /v1/pagamento/cartao/adicionar | muda | Como no cartão salvo. |
| cartao/validar/ · 3ds/checar/ B61 · B69 | POST /v1/pagamento/cartao/buscar | muda | Confirmar se "validar" faz hoje mais do que checar status. |
| pagamento/cartao/3ds/configurar/ B63 | POST /v1/pagamento/3ds/autenticacao POST /v1/pagamento/3ds/configuracao | muda | Vira duas chamadas. A primeira gera o merchantChargeId. |
| pagamento/cartao/3ds/desafio/ B64 | passos no navegador | muda | 3DS 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/consultar3DS | equivalente | Aprovado quando vêm eci e authentication.value. |
| pagamento/cartao/3ds/cobrar/ B66 | POST /v1/pagamento + merchantChargeId | muda | A 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/cancelar | muda | Regra de 23:59. |
| pagamento/cartao/3ds/consultar/ | GET /v1/pagamento/consulta/nit | equivalente | — |
PIX
| Hoje | API nova | Situação | O que muda |
|---|---|---|---|
| POST /api/generate-qrcodes B10 | POST /transacional/pix/qrcode | equivalente | Reais em decimal. Síncrono, até 30 s. |
| GET /api/find-qrcode/{id} B11 | GET /transacional/pix/consulta/{transactionId} | equivalente | Pago 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} | novo | Até 24 h devolve na hora; depois abre disputa. |
| — | POST /transacional/pix/disputa | novo | Só perfil Admin. Candidato a tela no painel. |
Cofre de cartões
| Hoje | API nova | Situação | O que muda |
|---|---|---|---|
| POST /Tokenizacao/CriarToken | POST /v1/pagamento/cartao/adicionar | muda | Exige authorizerId. |
| GET /Tokenizacao/ObterDadosToken/{token} | POST /v1/pagamento/cartao/buscar | muda | Só status. Confirmar se o cofre usa outro dado dessa resposta. |
| POST /Tokenizacao/Excluir/Token/{token} | DELETE /v1/pagamento/cartao/remover | equivalente | — |
| POST /v1/pagamento (validação) | POST /v1/pagamento | equivalente | Mesmo 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".
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.
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ção | Uso hoje | Impacto se for desligada |
|---|---|---|
Maquininha TEF: /Pdv/CriarOperacao, /Pdv/GetOperacao | Venda presencial (B47, B48) | Para a venda em POS da CredPay. |
Extrato: /Movimentacao/Analitico, /Consulta/Subdominio/Datas | Conciliação diária | A conciliação deixa de conferir o canal. |
Transferência bancária: /api/bank-transfers | B12 | Para a transferência por esse canal. |
Listagens: /Tokenizacao/Listar, /api/list-transactions | Consulta e sincronização | Passamos a depender só dos nossos registros. |
| Recorrência | Campos de recorrência no CheckOutPayReq | A 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ça | Hoje | API nova | O que fazer |
|---|---|---|---|
| Tokens de cartão | Criados em /Tokenizacao/CriarToken | Não está claro se valem em /v1/pagamento | Confirmar com a CredPay. Se não valerem, retokenizar pelo cofre antes da Fase 2. |
| Valores | Reais em BigDecimal (valorInicial) | Cartão em centavos (string); PIX em reais | Converter num único ponto do adaptador. |
| Identificadores | transacaoId, referenceId, numeroInterno | nit, merchantChargeId, customerId | Novas colunas no pedido e no cartão. |
| Prazo de estorno | Sem limite documentado | Cartã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. |
| Empresa | subDominioId, lojaId | Header Cliente-Id | Mapear cada comerciante; resolver uma vez por pedido e reutilizar. |
| 3DS | URL pronta | Formulários no navegador | Mudar o front. |
| Status | Rótulos do checkout | CONFIRMADO, AUTORIZADO, PENDENTE, NEGADO… | Tabela de conversão no adaptador. |
// 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ório | Mudança |
|---|---|
phiz-microwd-channel | Cliente 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-vault | Trocar CredpagamentosClient e CredpayClient pelo contrato novo, atrás de configuração. |
phiz-microwd-backapply | Gravar nit, merchantChargeId e customerId; adaptar CardCertifyServiceImpl ao 3DS novo; tratar o prazo de estorno. |
phiz-microwd-common | Colunas novas nas entidades de pedido e de cartão. |
phiz-inner e phiz-inner-front | Cadastro dos códigos e do road_info; tela de disputa PIX. |
| Front do 3DS | 3DS Method e desafio no navegador. |
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.
# 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
Preparação
- Levantar códigos CredPay ativos em
route_cfg - Chave de homologação
- Respostas da CredPay, principalmente sobre tokens
PIX
- Gerar QR e consultar
- Um comerciante de teste
- Devolução e disputa
Cartão sem 3DS
- Tokenização, pagamento, cancelamento, consulta
- Cofre de cartões
- Retokenização, se preciso
3DS
- Fluxo novo no channel
- Mudança no front
Pré-autorização
- Reservar, liquidar, desfazer
Desligamento
- Remover códigos antigos
- Remover
CredPayAuthTaske clientes antigos - TEF e conciliação seguem até haver substituto
Em cada fase
- Testes de contrato em homologação, usando a coleção Postman da CredPay como referência.
- Um comerciante piloto em produção, virado pela rota.
- Acompanhar taxa de aprovação, erros 4xx/5xx por código e tempo de resposta, comparando com o caminho antigo.
- 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
| Risco | Mitigação |
|---|---|
| Tokens antigos não valem na API nova | Confirmar na Fase 0; se for o caso, retokenizar pelo cofre antes da Fase 2. |
Cliente-Id diferente no meio do fluxo | Resolver 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:59 | Avisar no app e no painel; rotina de devolução fora da API. |
| Conciliação sem fonte de dados | Manter o extrato antigo até haver substituto. |
| Homologação apontando para produção | O 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
- Tokens. Tokens criados em
/Tokenizacao/CriarTokene no cofre valem em/v1/pagamento? Existe migração em lote? - Lacunas. Qual o substituto para TEF, extrato, transferência bancária e listagem de transações?
- Webhooks. Há notificação de confirmação para PIX e cartão, ou só consulta?
- Recorrência. Quais são as rotas do contrato de recorrência citado na documentação?
- 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. - Empresas. Como mapear nossos comerciantes para
Cliente-Id: uma chave por ambiente com todos vinculados, ou uma por comerciante? - Limites. Há limite de requisições por chave?
- 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.
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.
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-vaultwith the new card contract. - A cutover driven by the
route_cfgtable, 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.
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
- backapply looks up
route_cfgfor the transaction type, payment method and card BIN (RoadRouteServiceImpl.getRouteByTranPayAcct). The route says which provider and which service code handle it. - channel receives the code (for example
B21, payment with a saved card) and runs the Spring service registered under that name. - The service reads the provider base URL from
road_infoand calls CredPay.
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.
| # | Integration | Where | Login | Service codes |
|---|---|---|---|---|
| 1 | Checkout and saved cards | CheckOutTokenServiceImpl, CheckOutOperationServiceImpl, credPayRefactor/ | POST /AuthCredPay | B20–B25, B02, B03, Z519, Z520, Z523 |
| 2 | Pre-authorization | PreAuthService | checkout's | B26, B27, B28 |
| 3 | PIX, QR and bank transfer | service/credpay/ | POST /oauth/token | B10–B13 |
| 4 | Card with 3DS | ThreeDomainSecurePaymentService | autenticacao/gerar-token | B61–B70 |
| 5 | Card terminal (TEF) | TefService | checkout's | B47, B48 |
| 6 | Reconciliation | SynChannelDataService, Credpay*ReconciliationJob | /AuthCredPay/, hard-coded URL | jobs |
| 7 | Vault tokenization | card-vault: CredpagamentosClient | POST /AuthCredPay | — |
| 8 | Card verification | card-vault: CredpayClient | /v1/autenticacao/gerar-token | — |
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
| Topic | How it works |
|---|---|
| Base URL | https://api2-homolog.grupag.com.br (staging) and https://api2.grupag.com.br (production) |
| Authentication | API Key gpk_… in Authorization: Bearer. One per portal user, no expiry and no renewal. Regenerating it invalidates the previous one immediately. |
| Company | The 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. |
| Amounts | Card: cents as a string ("15000"). PIX: reais as a decimal (15.00). Simulation: cents as an integer. |
| Idempotency | Card: by orderId; two concurrent calls return 409. PIX: the same amount within a short window returns 409. |
| Responses | The envelope varies by family (details, data or root fields). Errors always use {message}. 502: no destination. 504: provider did not answer. |
# 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)# 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 flow05Goals 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
CredPayAuthTaskwith 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
Saved card and checkout
| Today | New API | Status | What changes |
|---|---|---|---|
| POST /Tokenizacao/CriarToken B20 · Z519 | POST /v1/pagamento/cartao/adicionar | changes | Requires 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/buscar | changes | Returns only the status (ATV or INA). |
| GET /Tokenizacao/Listar | — | no equivalent | See Gaps. |
| POST /Tokenizacao/Excluir/{id} B24 · Z520 | DELETE /v1/pagamento/cartao/remover | equivalent | DELETE with a {token, customer} body. |
| POST /Tokenizacao/Pagar B21 · B02 | POST /v1/pagamento | changes | Cents as a string; orderId required and idempotent; returns the nit, the new transaction key. |
| POST /Tokenizacao/Cancelar/{transacaoId}/{referenceId} B25 · B03 | DELETE /v1/pagamento/cancelar | changes | {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= | changes | By nit only. No lookup by internal number or orderId. |
| GET /Consulta/Subdominio/Datas/{ini}/{fim} | — | no equivalent | Used for reconciliation. |
{
"nomeDoCliente": "JOAO DA SILVA",
"documento": "12345678901",
"quantidadeDeParcelas": 1,
"valorInicial": 150.0,
"token": "TOKEN_DO_CARTAO",
"numeroInterno": "PED-4711",
"subDominioId": 1234,
"lojaId": 1
}{
"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
| Today | New API | Status | What changes |
|---|---|---|---|
| POST /Transacao/Autorizar B26 | POST /v1/pagamento/preautorizacao | equivalent | Same body as payment; starts as AUTORIZADO. |
| POST /Transacao/Capturar/{transacaoId}/{referenceId}/{valor} B27 | POST /v1/pagamento/preautorizacao/liquidar | equivalent | {nit, amount} body; partial capture allowed. |
| POST /Transacao/Cancelar/{transacaoId}/{referenceId} POST /Transacao/Cancelar/Parcial B28 | DELETE /v1/pagamento/cancelar | equivalent | One endpoint; the amount decides whether it is partial. Voiding a hold has no time limit. |
Card with 3DS
| Today | New API | Status | What changes |
|---|---|---|---|
| cartao/adicionar/ B62 | POST /v1/pagamento/cartao/adicionar | changes | Same as saved card. |
| cartao/validar/ · 3ds/checar/ B61 · B69 | POST /v1/pagamento/cartao/buscar | changes | Confirm whether "validar" does more than check the status today. |
| pagamento/cartao/3ds/configurar/ B63 | POST /v1/pagamento/3ds/autenticacao POST /v1/pagamento/3ds/configuracao | changes | Becomes two calls. The first creates the merchantChargeId. |
| pagamento/cartao/3ds/desafio/ B64 | browser steps | changes | 3DS Method and challenge are forms posted by the payer's browser. See section 07. |
| pagamento/cartao/3ds/checar/desafio/ B65 | GET /v1/pagamento/3ds/consultar3DS | equivalent | Approved when eci and authentication.value are present. |
| pagamento/cartao/3ds/cobrar/ B66 | POST /v1/pagamento + merchantChargeId | changes | The 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/cancelar | changes | 23:59 rule. |
| pagamento/cartao/3ds/consultar/ | GET /v1/pagamento/consulta/nit | equivalent | — |
PIX
| Today | New API | Status | What changes |
|---|---|---|---|
| POST /api/generate-qrcodes B10 | POST /transacional/pix/qrcode | equivalent | Reais as a decimal. Synchronous, up to 30 s. |
| GET /api/find-qrcode/{id} B11 | GET /transacional/pix/consulta/{transactionId} | equivalent | Paid 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} | new | Within 24 h it refunds immediately; after that it opens a dispute. |
| — | POST /transacional/pix/disputa | new | Admin profile only. Candidate for a panel screen. |
Card vault
| Today | New API | Status | What changes |
|---|---|---|---|
| POST /Tokenizacao/CriarToken | POST /v1/pagamento/cartao/adicionar | changes | Requires authorizerId. |
| GET /Tokenizacao/ObterDadosToken/{token} | POST /v1/pagamento/cartao/buscar | changes | Status only. Confirm whether the vault uses any other field of that response. |
| POST /Tokenizacao/Excluir/Token/{token} | DELETE /v1/pagamento/cartao/remover | equivalent | — |
| POST /v1/pagamento (verification) | POST /v1/pagamento | equivalent | Same 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".
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.
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.
| Operation | Used today for | Impact if switched off |
|---|---|---|
TEF terminal: /Pdv/CriarOperacao, /Pdv/GetOperacao | In-person sales (B47, B48) | CredPay POS sales stop. |
Statement: /Movimentacao/Analitico, /Consulta/Subdominio/Datas | Daily reconciliation | Reconciliation can no longer check this provider. |
Bank transfer: /api/bank-transfers | B12 | Transfers through this provider stop. |
Listings: /Tokenizacao/Listar, /api/list-transactions | Lookup and sync | We rely only on our own records. |
| Recurring payments | Recurrence fields in CheckOutPayReq | The docs mention a recurrence contract but not its routes. |
| Webhooks | — | Confirmation by polling only. |
10Breaking changes
| Change | Today | New API | What to do |
|---|---|---|---|
| Card tokens | Created in /Tokenizacao/CriarToken | Unclear whether they work in /v1/pagamento | Confirm with CredPay. If not, re-tokenize through the vault before Phase 2. |
| Amounts | Reais as BigDecimal (valorInicial) | Card in cents (string); PIX in reais | Convert in a single place in the adapter. |
| Identifiers | transacaoId, referenceId, numeroInterno | nit, merchantChargeId, customerId | New columns on orders and cards. |
| Refund window | No documented limit | Card: 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. |
| Company | subDominioId, lojaId | Cliente-Id header | Map each merchant; resolve once per order and reuse. |
| 3DS | Ready-made URL | Browser forms | Change the front end. |
| Status | Checkout labels | CONFIRMADO, AUTORIZADO, PENDENTE, NEGADO… | Conversion table in the adapter. |
// 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
| Repository | Change |
|---|---|
phiz-microwd-channel | HTTP 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-vault | Replace CredpagamentosClient and CredpayClient with the new contract, behind configuration. |
phiz-microwd-backapply | Store nit, merchantChargeId and customerId; adapt CardCertifyServiceImpl to the new 3DS; handle the refund window. |
phiz-microwd-common | New columns on the order and card entities. |
phiz-inner and phiz-inner-front | Register the codes and the road_info entry; PIX dispute screen. |
| 3DS front end | 3DS Method and challenge in the browser. |
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.
# 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
Preparation
- Inventory live CredPay codes in
route_cfg - Staging key
- CredPay's answers, especially on tokens
PIX
- Generate QR and poll
- One test merchant
- Refund and dispute
Card without 3DS
- Tokenization, payment, cancellation, lookup
- Card vault
- Re-tokenization, if needed
3DS
- New flow in the channel
- Front-end change
Pre-authorization
- Hold, capture, void
Decommission
- Remove old codes
- Remove
CredPayAuthTaskand old clients - TEF and reconciliation stay until there is a replacement
In every phase
- Contract tests in staging, using CredPay's Postman collection as the reference.
- One pilot merchant in production, switched by route.
- Watch approval rate, 4xx/5xx errors per code and response time, compared with the old path.
- 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
| Risk | Mitigation |
|---|---|
| Old tokens do not work in the new API | Confirm in Phase 0; if so, re-tokenize through the vault before Phase 2. |
Cliente-Id changes mid-flow | Resolve 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:59 | Warn in the app and panel; a routine for refunds outside the API. |
| Reconciliation with no data source | Keep the old statement until there is a replacement. |
| Staging pointing at production | The 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
- Tokens. Do tokens created in
/Tokenizacao/CriarTokenand in the vault work in/v1/pagamento? Is there a bulk migration? - Gaps. What replaces TEF, statements, bank transfers and transaction listings?
- Webhooks. Is there a confirmation notification for PIX and card, or only polling?
- Recurring. What are the routes of the recurrence contract mentioned in the docs?
- Simulation. Is
hashSimulacaochecked on payment? The simulation page says yes; the card page says it is accepted and ignored. - Companies. How should our merchants map to
Cliente-Id: one key per environment with all of them linked, or one key per merchant? - Limits. Is there a rate limit per key?
- 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.
将 CredPay 集成迁移到 GruPag API
把目前分散在四套 API、各自登录方式不同的 CredPay 路由,替换为新的 GruPag API:一个基础地址、一个 API Key、金额以分为单位,银行卡、3DS、预授权和 PIX 使用统一的接口规范。切换按操作逐项进行,通过内部管理后台的路由配置控制;每项操作验证通过之前,旧路径保持开启。
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 回答待定问题之前继续使用旧集成。
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
- backapply 按交易类型、支付方式和卡 BIN 在
route_cfg中查找路由(RoadRouteServiceImpl.getRouteByTranPayAcct)。路由决定由哪个渠道、哪个服务编码处理。 - channel 收到编码(例如
B21,已保存卡支付),执行以该名称注册的 Spring 服务。 - 该服务从
road_info读取渠道基础地址,然后调用 CredPay。
路径由数据而不是代码决定,所以新路径可以先以关闭状态上线,再按商户、按操作打开。回滚只需把这一行改回去。
03现有集成
以下清单来自 phiz-microwd-channel 和 phiz-pay-card-vault 的代码。
| # | 集成 | 位置 | 登录 | 服务编码 |
|---|---|---|---|---|
| 1 | 收银台与已保存的卡 | CheckOutTokenServiceImpl、CheckOutOperationServiceImpl、credPayRefactor/ | POST /AuthCredPay | B20–B25、B02、B03、Z519、Z520、Z523 |
| 2 | 预授权 | PreAuthService | 同收银台 | B26、B27、B28 |
| 3 | PIX、二维码与银行转账 | service/credpay/ | POST /oauth/token | B10–B13 |
| 4 | 3DS 银行卡 | ThreeDomainSecurePaymentService | autenticacao/gerar-token | B61–B70 |
| 5 | 刷卡终端(TEF) | TefService | 同收银台 | B47、B48 |
| 6 | 对账 | SynChannelDataService、Credpay*ReconciliationJob | /AuthCredPay/,地址写死在代码中 | 定时任务 |
| 7 | 保险库令牌化 | card-vault:CredpagamentosClient | POST /AuthCredPay | — |
| 8 | 卡片验证 | card-vault:CredpayClient | /v1/autenticacao/gerar-token | — |
代码只说明哪些接口可以被调用。生产环境实际启用了哪些编码取决于 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:渠道未响应。 |
# 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)# 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 flow05目标与非目标
目标
- 将银行卡、已保存的卡、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} | — | 无对应 | 用于对账。 |
{
"nomeDoCliente": "JOAO DA SILVA",
"documento": "12345678901",
"quantidadeDeParcelas": 1,
"valorInicial": 150.0,
"token": "TOKEN_DO_CARTAO",
"numeroInterno": "PED-4711",
"subDominioId": 1234,
"lojaId": 1
}{
"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/CriarToken | POST /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 用户裁决,因此需要在内部管理后台提供页面。
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-transfers | B12 | 经该渠道的转账停止。 |
列表:/Tokenizacao/Listar、/api/list-transactions | 查询与同步 | 只能依赖我们自己的记录。 |
| 周期扣款 | CheckOutPayReq 中的周期扣款字段 | 文档提到周期扣款合约,但没有给出路由。 |
| Webhook | — | 只能通过轮询确认结果。 |
10不兼容变更
| 变更 | 现在 | 新 API | 处理方式 |
|---|---|---|---|
| 卡令牌 | 在 /Tokenizacao/CriarToken 中创建 | 不确定能否在 /v1/pagamento 中使用 | 向 CredPay 确认。如不能,在第 2 阶段前通过保险库重新令牌化。 |
| 金额 | 雷亚尔,BigDecimal(valorInicial) | 银行卡为分(字符串);PIX 为雷亚尔 | 在适配器中集中一处转换。 |
| 标识 | transacaoId、referenceId、numeroInterno | nit、merchantChargeId、customerId | 在订单和卡片表中新增字段。 |
| 退款时限 | 文档无明确限制 | 银行卡:当天 23:59 前。PIX:超过 24 小时进入争议。 | 在 App 和管理后台中处理;提供 API 之外的退款流程。 |
| 公司 | subDominioId、lojaId | 请求头 Cliente-Id | 为每个商户建立映射;每个订单只解析一次并复用。 |
| 3DS | 现成地址 | 浏览器表单 | 修改前端。 |
| 状态 | 收银台的状态值 | CONFIRMADO、AUTORIZADO、PENDENTE、NEGADO… | 在适配器中维护转换表。 |
// 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,并在约定的窗口期内更换。
# 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迁移计划
准备
- 在
route_cfg中盘点在用的 CredPay 编码 - 测试环境密钥
- CredPay 的答复,尤其是令牌问题
PIX
- 生成二维码与轮询
- 一个测试商户
- 退款与争议
无 3DS 银行卡
- 令牌化、支付、取消、查询
- 卡片保险库
- 必要时重新令牌化
3DS
- channel 中的新流程
- 前端改动
预授权
- 冻结、请款、撤销
下线
- 移除旧编码
- 移除
CredPayAuthTask和旧客户端 - TEF 和对账在有替代方案前保留
每个阶段
- 在测试环境做接口契约测试,以 CredPay 的 Postman 集合为参考。
- 在生产环境选一个试点商户,通过路由切换。
- 与旧路径对比,观察授权成功率、各编码的 4xx/5xx 错误和响应时间。
- 分批切换其余商户。
具体日期在第 0 阶段之后确定,届时我们会知道哪些编码在用以及 CredPay 的答复。
13风险
| 风险 | 应对 |
|---|---|
| 旧令牌在新 API 中不可用 | 在第 0 阶段确认;如不可用,在第 2 阶段前通过保险库重新令牌化。 |
流程中途 Cliente-Id 不一致 | 每个订单只解析一次,保存并复用;对完整 3DS 流程做自动化测试。 |
| 金额单位错误(雷亚尔与分) | 只在一处转换,并按接口做契约测试。 |
| 23:59 之后退款被拒 | 在 App 和管理后台中提示;提供 API 之外的退款流程。 |
| 对账缺少数据来源 | 在有替代方案前保留旧的流水接口。 |
| 测试环境指向生产 | card-vault 目前默认使用生产地址,因为当时测试环境不可用。新 API 在非生产环境必须使用测试地址。 |
14需要 CredPay 回答的问题
- 令牌。在
/Tokenizacao/CriarToken和保险库中创建的令牌能否在/v1/pagamento中使用?是否支持批量迁移? - 缺口。TEF、流水、银行转账和交易列表的替代方案是什么?
- Webhook。PIX 和银行卡是否有结果通知,还是只能轮询?
- 周期扣款。文档中提到的周期扣款合约有哪些路由?
- 模拟。支付时是否校验
hashSimulacao?模拟页面说会校验,银行卡页面说会接收但忽略。 - 公司。我们的商户如何对应到
Cliente-Id:每个环境一个密钥并关联所有商户,还是每个商户一个密钥? - 限流。每个密钥是否有请求频率限制?
- 时间表。现有 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。