Gateway Bancário Real (Fiducia) — Sandbox e Produção
App\Models\Banks\Fiducia (fastgivr-api) é o adapter real de BankInterface — a alternativa ao gateway Teste (mock 100% local, sem rede). Contrato de referência: API_de_Contas_-_Integracao.postman_collection.json (~150 endpoints; a Fiducia SCM é o único provedor de "conta bancária real" documentado neste repositório).
Status: implementado e não testado contra o ambiente real — a coleção Postman não tem nenhum exemplo de resposta salvo para os endpoints usados aqui, só os payloads de requisição. Ver Antes de ligar em produção antes de habilitar contra dinheiro de verdade, e o Plano de Execução para as fases e critérios de saída até chegar lá.
Os dois modos
Mesma classe, mesmo código — só muda a base URL. Controlado por FIDUCIA_MODE (config('banks.fiducia.mode')):
| Modo | Base URL | O que significa |
|---|---|---|
sandbox (padrão) | FIDUCIA_SANDBOX_BASE_URL — https://api.contashoml.fiduciascm.digital:8609 | Ambiente de homologação real do provedor. Chamadas de rede de verdade, contra a infraestrutura da Fiducia, mas sem movimentar dinheiro real. É o ambiente descrito na coleção Postman. |
production | FIDUCIA_PRODUCTION_BASE_URL (vazia por padrão) | Dinheiro real. Fiducia::baseUrl() recusa iniciar se FIDUCIA_MODE=production e essa variável estiver vazia — para nunca cair em produção por omissão de configuração. |
Não confundir com BANK_SANDBOX (config('banks.sandbox')): essa outra flag já existia e decide se o cadastro (/access/register/submit) é aprovado automaticamente ou fica UNDER_REVIEW. É ortogonal ao modo do gateway — uma conta pode estar em BANK_SANDBOX=true (aprovação automática) e mesmo assim operar contra FIDUCIA_MODE=production, ou vice-versa. Também não confundir com gateways/bank_gateway: uma conta só usa o adapter Fiducia (sandbox ou produção) se accounts.bank_gateway = 'Fiducia' — o padrão do produto continua sendo Teste.
Duas credenciais, dois lugares
| Credencial | Onde fica | Uso |
|---|---|---|
Sistêmica — FIDUCIA_CLIENT_ID / FIDUCIA_CLIENT_SECRET | .env (config/banks.php) | POST /auth/token — reservada para operações administrativas (gestão de contas/credenciais). Não usada pelo adapter hoje — BankInterface não cobre onboarding de conta na Fiducia, só operação de contas já existentes. Guardada para quando esse escopo for implementado. |
Por conta — login (cpfcnpj/conta/password/cod_operador) | accounts.document + accounts.account (já existiam) + accounts.bank_login_password + accounts.bank_operator_code (novas, criptografadas — cast encrypted no Eloquent) | POST /login — autentica como aquela conta. Todo Pix/boleto/transferência é feito com esse bearer. |
O bearer obtido no login é cacheado em accounts.token / accounts.token_expires (colunas que já existiam, pensadas exatamente para isso — só não eram usadas por nenhum gateway real ainda). Fiducia::getAccessToken() só chama /login de novo quando token_expires expira — "cálculo de tempo de sessão". token foi ampliado de VARCHAR(255) para TEXT (JWT real não cabe em 255 caracteres) na migration 2026_09_09_000001_add_fiducia_credentials_to_accounts_table.
accounts.bank_login_password / bank_operator_code estão em Account::$hidden — nunca saem em toArray()/toJson()/respostas de API.
Antes de operar uma conta em modo Fiducia, alguém precisa gravar o login daquela conta especificamente:
$account->forceFill([
'bank_gateway' => 'Fiducia',
'bank_login_password' => '...', // senha de login da Fiducia (não a senha transacional)
'bank_operator_code' => '...', // cod_operador
])->save();A senha transacional (transational_password nos payloads da Fiducia — confirmação por PIN de cada operação que move dinheiro) reaproveita o campo que já existe: accounts.pin.
Mapeamento método → endpoint
Todo método de BankInterface implementado por Fiducia, mais os métodos extra que o app chama via Account::getBank()->...() sem passar pela interface (Pix in/out, gestão de chave, etc. — mesmo padrão que Teste já cobre). "Confirmado" = testado contra o ambiente real; hoje nenhum está.
| Método PHP | Endpoint Fiducia | Confirmado? |
|---|---|---|
getAccessToken() | POST /login | Requisição sim, resposta não |
createPixDinamico() | POST /pix/qrcode/dinamico/imediato/gerar | Requisição sim, resposta não |
createPixComVencimento() | POST /pix/qrcode/dinamico/vencimento/gerar | Requisição sim, resposta não |
getPixCharge($location) | GET direto na URL da location (fora da API Fiducia — por especificação do Pix) | Sim (spec BCB) |
getPixTransactionDetails() | GET /pix/dict/gestao-chave/{chave}/oculto | ⚠️ Melhor palpite — ver nota abaixo |
makePixTransfer() / makePixTransferBank() | POST /pix/spi/transferir | Requisição sim, resposta não; tipo_iniciacao/tipo_chave não documentados (ver nota) |
getPixRefundReasons() | GET /pix/spi/devolver/motivos | Requisição sim, resposta não |
refundPix() | POST /pix/spi/devolver | Requisição sim, resposta não |
createPixKey() / deletePixKey() / listPixKeys() | POST /pix/dict/gestao-chave/incluir, DELETE .../excluir, GET .../listar | Requisição sim, resposta não |
claimPixKey() / confirmPixKeyClaim() / cancelPixKeyClaim() / listPixKeyClaims() | .../reivindicacao/incluir|:id/confirmar|:id/cancelar|listar | Requisição sim, resposta não |
makeBoleto() | POST /boleto (Gerar boleto de cobrança) | Requisição sim, resposta não |
makeBoletoDeposito() | POST /boleto/deposito | Requisição sim, resposta não |
fetchBoleto() | GET /boleto/{nossoNumero} | Requisição sim, resposta não |
consultarBoleto() / getBoletoDetails() | POST /pagamentos/autorizar (consulta sem debitar) | Requisição sim, resposta não |
pagarBoleto() / payBoleto() | POST /pagamentos/autorizar (se faltar transactionIdAuthorize) + POST /pagamentos/efetivar | Requisição sim, resposta não |
consultarComprovante() | GET /pagamentos/consultar/{id} | Requisição sim, resposta não |
cancelarAgendamento() | DELETE /pagamentos/pendente/{id} | Requisição sim, resposta não |
makeBankTransfer() | POST /transferencia | Requisição sim, resposta não |
getBankTransferStatus() / cancelBankTransfer() | GET/DELETE /transferencia/agendada/{numCtrlIF} | ⚠️ Só cobre transferência agendada — ver lacuna abaixo |
printBoletoPdf() | — | Sem endpoint na coleção; devolve null (fallback já esperado pelos chamadores) |
consultarBoletosDDA() | — | Sem endpoint na coleção; devolve [] |
endWithdraw() | — | Sem endpoint na coleção nem uso real no app hoje; lança BankException em vez de simular sucesso |
⚠️ Lacunas e suposições conhecidas
A coleção Postman documenta requisição, não resposta — nenhum dos ~150 endpoints tem exemplo de resposta salvo. Tudo abaixo precisa ser validado contra chamadas reais no sandbox de homologação antes de qualquer uso em produção (o código já marca cada ponto com // RESPOSTA NÃO CONFIRMADA):
- Nomes de campo na resposta —
Fiducialê a resposta com fallback ($response->json('token') ?? $response->json('access_token') ?? ...), mas são palpites. Se a Fiducia usar um nome de campo fora dessas variantes, o método falha com "resposta sem token reconhecível" em vez de silenciosamente aceitar dado errado — intencional, mas precisa ser corrigido assim que a resposta real for vista. - Códigos de
tipo_chave/tipo_iniciacaodo Pix — a coleção usatipo_chave: 3(Transferir Pix) etipo_chave: 4(Incluir chave no DICT) sem tabela de referência.Fiducia::identifyPixKeyType()/pixKeyTypeCode()assumem a ordem mais comum entre provedores DICT (CPF/CNPJ=0, telefone=1, e-mail=2, aleatória=3) — pode estar errado. Confirmar com o suporte da Fiducia ou por tentativa no sandbox. - Status de transferência instantânea — a coleção só expõe
GET /transferencia/agendada/:numCtrlIF(transferências agendadas). Não há endpoint de status para uma transferência instantânea já efetivada; a fonte da verdade seria o extrato (GET /conta/extrato/...), fora do escopo deBankInterfacehoje. - DDA e segunda via de boleto em PDF — sem endpoint correspondente na coleção. Degradam para
[]/null(mesmo contrato que os chamadores já esperam do gatewayTestepara casos não suportados), não erro 500. getPixTransactionDetails()— mapeado para "Consultar chave" (/pix/dict/gestao-chave/:chave/oculto), que fica na pasta de gestão das próprias chaves da conta. Não está confirmado que esse endpoint também resolve chaves de terceiros (necessário para mostrar o nome do destinatário antes de um Pix out) — pode ser preciso outro endpoint do DICT que não foi identificado na coleção.
Antes de ligar em produção (checklist)
- [ ] Validar cada linha "Requisição sim, resposta não" da tabela acima contra o sandbox real da Fiducia; ajustar o parsing de resposta em
App\Models\Banks\Fiduciaconforme os nomes de campo reais. - [ ] Confirmar a tabela de
tipo_chave/tipo_iniciacaodo Pix com a Fiducia. - [ ] Resolver a lacuna de status de transferência instantânea (item 3 acima) antes de expor
getBankTransferStatus()para transferências não agendadas. - [ ] Preencher
FIDUCIA_PRODUCTION_BASE_URLsó quando a conta de produção estiver liberada — o adapter recusa iniciar emproductionsem essa URL. - [ ] Nunca reusar credenciais de sandbox (
bank_login_password/bank_operator_code/client_secret) em contas de produção nem vice-versa. - [ ] Migrar a coluna
accounts.bank_login_passwordcom um plano de rotação de senha — se a senha de login da Fiducia mudar (ex.: exigência de troca periódica do provedor), o app precisa de um fluxo para atualizá-la sem downtime.
Ver também
- Plano de Execução — Gateway Bancário Real — fases, critérios de saída e riscos até a produção
- Contrato de referência (Postman)
config/banks.php— configuração dos dois gatewaysApp\Interfaces\BankInterface— contrato que todo gateway implementa- Banco de Dados — Histórico de Correções — mesmo padrão de "o que foi feito / o que falta confirmar"