Especificação · Fornecedores

Cadastro de Fornecedor

Quem é o fornecedor, se ele está apto a vender, e para onde o dinheiro vai. Três perguntas que o sistema de compras precisa responder — e que param exatamente onde começa o ERP financeiro.

substitui o módulo Fornecedores mínimo 9 agregados · 2 entidades de configuração alinhada a Anexo e GrydFiles · decidida por Fluxo de Aprovação v3.10 · 30/10/2026

Ponto de partida

Seis decisões que estruturam o resto

Decisão 1 · Identidade

Dois níveis: Supplier e SupplierEstablishment. Fornecedor é a entidade jurídica, chaveada pela raiz de 8 do CNPJ quando tem CNPJ — pelo CPF ou pelo identificador do país nos outros tipos; estabelecimento é o CNPJ completo de 14, matriz ou filial, e é onde vivem o endereço fiscal, a IE por UF, os termos comerciais e o padrão de pedido — por isso todo tipo de pessoa tem ao menos um, com ou sem CNPJ. Certidão federal, CNDT, regime tributário e quadro societário vivem na raiz. Situação cadastral, inscrição estadual, inscrição municipal, alvará e licença ambiental vivem no estabelecimento — e uma filial pode estar baixada com a matriz ativa.

Decisão 2 · CNPJ alfanumérico

Isso já está valendo. A IN RFB 2.229/2024 pôs o CNPJ alfanumérico em produção em 31/07/2026. Coluna VARCHAR(14), nunca numérica; os 12 primeiros caracteres aceitam A–Z, os 2 DV continuam numéricos; o DV usa ASCII − 48. A maioria das bibliotecas de validação de CNPJ ainda não implementa isso.

Decisão 3 · Prospect

Cotar não exige homologar. Dois estados de relacionamento, no modelo da Oracle: Prospect participa de RFQ e de qualificação mas não recebe pedido; SpendAuthorized transaciona. É a mudança de maior retorno sobre o modelo atual — desbloqueia cotação sem o atrito de exigir dez certidões de quem talvez nem venda.

Decisão 4 · Evidência

Documento enviado ≠ verificação feita. São duas entidades. SupplierDocument é o PDF que o fornecedor subiu; SupplierVerification é a consulta que o Nexio fez numa fonte oficial, com carimbo de data, fonte e resultado. Níveis de confiança diferentes, retenções diferentes e telas diferentes.

Decisão 5 · Banco

Dado bancário muda por proposta, nunca por edição. A alteração é escrita numa tabela de proposta e o registro vivo não muda até a instância do motor aprovar, vendo o diff, depois do aviso ao canal anterior e do callback — ou, sem telefone confiável, com a controladoria e prova documental. Mesma regra na tela, na API e na importação — o núcleo bancário não é configurável, e a carga inicial de implantação é a única exceção, declarada. É o padrão do D365 e é o único controle estrutural contra a fraude de troca de conta. Quem decide é o motor de aprovação — processo BANK_ACCOUNT_CHANGE —; titularidade, callback, carência, DICT e aviso no canal anterior são daqui.

Decisão 6 · Motor

Toda aprovação deste módulo é uma instância do motor de aprovação. Cadastro (SUPPLIER_REGISTRATION), homologação (SUPPLIER) e alteração bancária (BANK_ACCOUNT_CHANGE) não têm rota própria de aprovar: o Fornecedor submete, o motor decide — quem, em que ordem, em quanto tempo, com que alçada —, e o Fornecedor aplica o efeito. Bloquear e desbloquear continuam atos de uma pessoa só, com motivo: não são aprovação. Ver Fluxo de Aprovação, princípio 7.

Fundamentos

Sete princípios

1. O Nexio é dono da identidade e da aptidão; o ERP é dono da obrigação e do pagamento

O cadastro guarda os fatos que sustentam "podemos comprar deste fornecedor, com que risco, e para onde pagamos" — e a evidência dessa decisão. Título a pagar, aging, retenção calculada, conta contábil, DARF, CNAB e escrituração são do ERP. Boa parte dos campos que Oracle, SAP e D365 carregam no fornecedor existe para servir ao módulo financeiro; copiá-los é o erro clássico de quem modela olhando ERP.

2. Certidão vence sozinha; status é derivado

A data de vencimento do documento é a fonte da verdade — o status do processo de homologação nunca a influencia. Isso é explícito na documentação do Ariba e evita o estado impossível "homologação aprovada com certidão vencida".

3. Homologação é por categoria, não global

Homologar "o fornecedor" é o antipadrão. Um fornecedor de serviço de limpeza e um de matéria-prima química exigem evidências diferentes. Ariba escopa qualificação por commodity + região; Oracle organiza áreas de qualificação em rule sets. Requalificação preserva o mesmo escopo da qualificação anterior.

4. Não existe rol legal fechado de documentos no setor privado

Diferente de licitação pública, cada comprador define seu pacote. O Nexio não pode ter lista de documentos codificada: precisa de requisitos configuráveis por tenant × categoria × faixa de risco. Lista fixa perde cliente de setor regulado por não coletar o que ele precisa, e irrita cliente de serviço leve por exigir o que não faz sentido.

5. Sanção pública alerta; não bloqueia sozinha

CEIS, CNEP e CEPIM são sanções em contratação pública. Uma empresa listada não está legalmente impedida de vender para uma empresa privada. No privado esses cadastros são sinal reputacional: geram alerta e decisão registrada. Bloqueio automático produz falso positivo, e o time de compras aprende a ignorar o alerta — que é o pior resultado possível de um controle.

6. CNAE não autoriza atividade

CNAE é classificação estatística e fiscal. Quem autoriza é alvará, licença setorial e conselho de classe. Use CNAE como triagem e como sinal de alerta quando o objeto contratado não guarda relação com nenhum CNAE do fornecedor — nunca como bloqueio duro, que reprova fornecedor legítimo e aprova o irregular que tem o CNAE certo e nenhuma licença.

7. O que o fornecedor declara e o que ele está autorizado a vender são coisas diferentes

As categorias declaradas no cadastro — pelo comprador, na v1 — servem para descoberta — montar a lista de convidados de um RFQ. O que ele pode de fato ter comprado é o ItemSupplier e a homologação por categoria. Fundir as duas transforma um campo declarado sem verificação em controle de compliance.

Modelo

Mapa de entidades

SupplierEstablishment N por fornecedor CNPJ de 14, matriz ou filial — ou sem CNPJ, para quem não tem. Situação cadastral, IE, IM, endereço fiscal, termos comerciais, padrão de pedido.
SupplierContact N · papéis Pessoa com papéis (comercial, fiscal, financeiro, técnico, admin do portal). Opcionalmente ligado a um PortalUser.
SupplierDocument N · com vencimento O que o fornecedor enviou. Tipo configurável, vigência, arquivo, status derivado da data.
SupplierAddress N · flags de propósito Sede, entrega, cobrança, RFQ — flags independentes, não enum.
Supplier aggregate root · raiz do CNPJ Pessoa jurídica ou física. Razão social, natureza, porte, CNAE, regime tributário; grupo econômico por parentSupplierId.
SupplierVerification N · append-only O que o Nexio consultou: fonte, data, resultado, evidência. Nunca sobrescrito.
SupplierComplianceAlert N · com decisão Achado de varredura — sanção, situação cadastral, divergência com o ERP — aberto até decisão registrada (RN-FOR-37).
SupplierBankAccount versionado Conta e chave PIX com vigência. Alterado por BankAccountChangeProposal, nunca por update — e a proposta é decidida pelo motor (BANK_ACCOUNT_CHANGE).
SupplierQualification por categoria Escopo, questionário, resultado, validade, requalificação. A decisão por área é uma instância do motor (SUPPLIER).
ItemSupplier ponte com o Catálogo Preço, prazo, MOQ, múltiplo, unidade de compra. Detalhado em § Item × Fornecedor.
Contas a pagar fora de escopo Título, aging, retenção calculada, conta contábil, CNAB, escrituração.
SupplierCategory declarativa O que ele diz que fornece. Serve para descoberta e convite a RFQ — não autoriza compra.
PortalUser credencial · 0..1 por contato Separado do contato. Login, status da conta, escopo de acesso.

O Supplier é dono de anexo (ownerType = Supplier) — da evidência avulsa: ata de visita técnica, correspondência, e-mail de negociação, parecer solto. SupplierQualification também é dona — a evidência do ciclo de homologação. Certidão, contrato social e cartão de CNPJ continuam SupplierDocument, pela mesma regra de corte: o que tem número, órgão e vigência para digitar é entidade; o que é só prova é anexo. A BankAccountChangeProposal também é dona — o comprovante de titularidade que o controle antifraude exige antes da submissão, no tipo de anexo BANK_OWNERSHIP_PROOF, declarado no Anexo com retenção e marca de prova de controle — é pelo tipo que a submissão reconhece o comprovante, e anexo de outro tipo, GENERAL inclusive, não vale como titularidade. O pedido de troca de contato sem telefone confiável segue a mesma regra, no tipo SIGNED_CONTACT_CHANGE_REQUEST (RN-FOR-34), e a correção de identidade, no tipo IDENTITY_CORRECTION_PROOF, cujo dono é o próprio Supplier e que segue a matriz geral de leitura de anexo do fornecedor (RN-FOR-39). Em nenhum dos dois o sistema confere o documento: exige o anexo do tipo declarado, liberado pelo antivírus, e grava o rastro — quem anexou, quem decidiu, data e hora. Na carga inicial, a dona do comprovante é a proposta criada pela linha (RN-FOR-31). As respostas de cada descritor estão declaradas na página do Anexo, em O dono polimórfico — este módulo implementa, não redecide.

Convenção de nomes. O documento é em português; os identificadores são em inglês — entidades, atributos, valores de enum, rotas, permissões e códigos de erro. A exceção são os dados de negócio brasileiros, que ficam como são no mundo real: identificadores fiscais (cnpj, cpf, primaryCnae), nomes de regime tributário (SimplesNacional, LucroReal), siglas de unidade (UN, CX, KG), tipos de certidão e os exemplos de taxonomia — esses são conteúdo, não código.

A decisão central

Fornecedor e estabelecimento

A Oracle separa Supplier (entidade legal global) de Supplier Site (unidade que transaciona, com condição de pagamento, moeda e tolerâncias próprias). Esse modelo não mapeia direto para o Brasil: no Oracle o CNPJ mora no fornecedor e o site não tem identificação fiscal própria — mas aqui cada filial que emite nota tem CNPJ próprio e situação cadastral própria.

Vive na raiz (Supplier)Vive no estabelecimento
Razão social, natureza jurídica, porte, data de aberturaCNPJ completo (14), matriz ou filial
CNAE principal e secundáriosSituação cadastral e data — uma filial pode estar baixada com a matriz ativa
Regime tributário, opção pelo Simples, opção pelo regime regular de IBS/CBSInscrição estadual (por UF) e inscrição municipal
Quadro societárioEndereço fiscal
CND federal, CRF do FGTS, CNDTCertidão estadual e municipal, alvará, licença ambiental, licenças setoriais
Grupo econômico, DUNS, LEICapacidade de entrega, contatos operacionais

A raiz é a pessoa jurídica; grupo econômico é outra coisa

A raiz de 8 caracteres do CNPJ identifica a pessoa jurídica — matriz e filiais a compartilham. Por isso cnpjRoot é único por tenant: ao cadastrar um CNPJ cuja raiz já existe na base, o Nexio recusa o fornecedor novo e oferece adicionar o estabelecimento ao fornecedor existente. Dois Supplier com a mesma raiz duplicariam as certidões federais, a homologação e o histórico de gasto, e disparariam contra si mesmos o alerta "mesma conta em fornecedores distintos". Grupo econômico é o que liga raízes distintas — holding e controladas —, e para isso existe parentSupplierId autorreferente, no modelo da Oracle e da Coupa.

O que o Nexio não vai construir agora: o "site" comercial

SAP e NetSuite particionam o fornecedor por unidade do comprador (company code, purchasing org, subsidiary). Num SaaS multi-tenant o tenant já é o comprador — replicar isso dentro do tenant só se paga com clientes que tenham várias filiais compradoras de fato. A evidência de que precisa vem quando o ItemSupplier precisar variar por local de entrega, que é o eixo ship-to organization da ASL da Oracle — e ela já veio: a UF de destino e a empresa compradora são eixos do preço — os dois na chave do ItemSupplierPrice, não na da relação. Condição de pagamento, moeda e incoterm continuam no estabelecimento porque nunca variaram por comprador; o preço, que varia, saiu de lá.

O tipo de pessoa muda o formulário inteiro

Company | MEI | Individual | RuralProducer | Foreign não é um campo com metade dos outros opcionais: é o seletor que decide quais campos existem, quais certidões são exigidas e quais alertas aparecem. Fornecedor estrangeiro não tem CNPJ, IE, IM, CND, FGTS, CNDT, CNAE nem Simples — forçar esses campos como obrigatórios é o bug mais comum de cadastro multi-país.

Domínio

Campos

Legenda: obrig · cond conforme tipo de pessoa · opc · gerado preenchido por consulta ou cálculo.

Fornecedor — identificação

CampoTipoRegra
entityTypeenumobrigCompany | MEI | Individual | RuralProducer | Foreign. Governa a obrigatoriedade de todo o resto. Imutável depois da aprovação do cadastro (RN-FOR-39).
cnpjRootvarchar(8)?condDerivado do CNPJ do estabelecimento principal, só para Company e MEI; nulo para Individual, RuralProducer e Foreign, que se identificam na raiz. São oito caracteres, não dígitos. Único por tenant onde não nulo: a raiz identifica a pessoa jurídica, e matriz e filiais são estabelecimentos do mesmo Supplier, nunca fornecedores distintos. Imutável depois de criada. Grupo econômico não é a raiz — é parentSupplierId. Ver RN-FOR-33.
legalNamestring(200)obrigPreenchido automaticamente pela consulta ao CNPJ quando disponível. Em Foreign é o nome contra o qual a RN-FOR-13 compara o titular da conta, e fica imutável depois da aprovação do cadastro (RN-FOR-39).
tradeNamestring(200)opcÉ por ele que o comprador busca. Indexado na busca full-text.
cpfchar(11)condObrigatório para Individual e RuralProducer, e é a identidade deles: único por tenant onde não nulo. Imutável depois da aprovação do cadastro (RN-FOR-39). Dado pessoal — ver LGPD.
ownerCpfchar(11)?condObrigatório para MEI e só para ele: o CPF do empresário individual, que no mundo real é o titular da conta do MEI (RN-FOR-13). Validado por DV — inválido responde 400 SUPPLIER_CPF_INVALID. Imutável depois da aprovação do cadastro (RN-FOR-39). Dado pessoal — ver LGPD.
foreignTaxId / taxIdCountrystring(40) / char(2)condObrigatórios para Foreign, e são a identidade dele: o par é único por tenant onde não nulo. Sem DV nacional — validação por formato do país. ISO 3166. Imutáveis depois da aprovação do cadastro (RN-FOR-39).
legalNatureCodestring(4)opcCódigo da tabela da Receita. Vem da consulta.
companySizeenumopcNotInformed | ME | EPP | Other. Notoriamente desatualizado na base da Receita — indicativo, nunca verdade contratual.
foundedOndateopcEmpresa aberta há poucos meses é sinal de triagem, não de reprovação.
primaryCnae / secondaryCnaeschar(7) / char(7)[]opcSubclasse CNAE de 7 dígitos. Triagem e sugestão de categoria — nunca habilitação.
duns / leiCodechar(9) / char(20)opcIdentificadores globais, relevantes em fornecedor estrangeiro.
bankProposalsBlockedAt / bankProposalsBlockedByProposalIddatetime? / Guid?geradoPreenchidos quando uma mudança de contato já aplicada é contestada; enquanto preenchidos, nenhuma proposta de conta é criada ou submetida, e toda troca de canal passa pela instância com a controladoria. Limpos só pelo desfecho que aplica essa troca. Ver RN-FOR-38.
pendingIdentityCorrectionobj?geradoCorreção de identidade em aprovação: entityType, cpf, ownerCpf e, em Foreign, legalName e foreignTaxId/taxIdCountry propostos — nunca CNPJ —, justificativa, o identificador do anexo comprobatório, quem pediu (usuário e chave de pessoa), quando e a instância. Uma por vez; limpa pelo desfecho. Ver RN-FOR-39.
identityCorrectionLinkedPeopleobj[]geradoQuem pediu e quem decidiu correção de identidade: usuário, chave de pessoa (nunca o CPF em claro), papel (Requester | Decider), instância e a data do desfecho. Sem prazo: a ligação vale enquanto o fornecedor existir. Só cresce; lido pelas guardas de conta e de canal, e copiado do antecessor quando o fornecedor nasce como sucessor. Ver RN-FOR-41.
supersedesSupplierIdGuid?opcDeclarado na criação e imutável: o fornecedor inativado do mesmo tenant que este substitui — o caminho da troca de tipo de pessoa que a correção de identidade não alcança (RN-FOR-39). Um sucessor por antecessor, sem ciclo. Faz o fornecedor novo nascer com o identityCorrectionLinkedPeople do antecessor. Não é grupo econômico, que é parentSupplierId.
parentSupplierIdGuid?opcAutorreferência, e o único significado de "grupo econômico" no Nexio: liga pessoas jurídicas distintas, de raízes diferentes. Mesma raiz nunca é grupo — é o mesmo fornecedor. Sem ciclo e sem apontar para a própria raiz (RN-FOR-33).

Identidade por tipo de pessoa

entityTypeIdentidadeOnde viveUnicidade
Company · MEIcnpjSupplierEstablishment, um por CNPJ de 14; cnpjRoot derivado na raizcnpj único por tenant, entre os estabelecimentos; cnpjRoot único por tenant, entre as raízes
Individual · RuralProducercpfSupplierúnico por tenant, entre as raízes
ForeigntaxIdCountry + foreignTaxIdSuppliero par, único por tenant, entre as raízes

Três identidades, cada uma com o seu índice único parcial por tenant — onde a coluna não é nula. Índice parcial depende do banco; a verificação vale na aplicação, inclusive contra rascunhos e cadastros pendentes (ver Antiduplicidade). cnpjRoot, cnpj, establishmentType e registrationStatus são nulos fora de Company e MEI; cpf só existe em Individual e RuralProducer; taxIdCountry + foreignTaxId só em Foreign. O estabelecimento continua obrigatório para todo tipo — ver RN-FOR-02.

Fornecedor — tributário

CampoTipoRegra
taxRegimeenumopcSimplesNacional | MEI | LucroPresumido | LucroReal | TaxExempt | NotApplicable. Obtido dos dados abertos da Receita (tabela do Simples traz opção e datas).
optsForRegularIbsCbsRegimebool?opcCampo decisivo. Sob a LC 214/2025, optante do Simples que recolhe IBS/CBS dentro do DAS não permite crédito ao comprador; se optar pelo regime regular, o crédito é integral. Dois orçamentos de mesmo valor bruto podem ter custo líquido diferente por causa disso. Praticamente nenhum cadastro de fornecedor tem esse campo hoje.
regularRegimeOptedOndate?condObrigatória quando o anterior é verdadeiro — a opção tem data e afeta comparativos retroativos.

Estabelecimento

CampoTipoRegra
cnpjvarchar(14)?condObrigatório para Company e MEI; nulo para Individual, RuralProducer e Foreign, cuja identidade vive na raiz. Nunca numérico. Regex ^[A-Z0-9]{12}[0-9]{2}$, gravado sem máscara e em caixa alta. DV por módulo 11 com valor do caractere = ASCII − 48 (assim A–Z valem 17–42). Caso de teste canônico da Receita: 12ABC34501DE → DV 35. Índice único por tenant onde não nulo — parcial, depende do banco.
establishmentTypeenum?geradoHeadquarters | Branch, lido do identificador matriz/filial da Receita (1 = matriz, 2 = filial) devolvido pela consulta ao CNPJ — nunca derivado da ordem 0001: com o CNPJ alfanumérico, e já hoje nas transferências de sede, a matriz pode ter outra ordem. Sem verificação registrada fica nulo, e enquanto nulo nada que dependa de "ser matriz" é inferido. Nulo também para quem não tem CNPJ; ali o único estabelecimento é o principal, marcado por isPrimary.
registrationStatus / registrationStatusOnenum? / date?geradoRegistrationStatus = 01 Null | 02 Active | 03 Suspended | 04 Unfit | 08 ClosedDown, os códigos da Receita — o mesmo enum do Establishment comprador. Só Active deveria homologar. É por estabelecimento, não por raiz; nulo para quem não tem CNPJ — não existe situação cadastral sem cadastro.
stateRegistrationStatus / stateRegistrationNumber / stateRegistrationUfenum / string(20) / char(2)condstateRegistrationStatus ∈ {HasRegistration, Exempt, NotApplicable, NotInformed}. Uma IE por estabelecimento: fornecedor com IE em várias UFs as tem em estabelecimentos diferentes. Em RuralProducer a IE (UF + número) identifica o estabelecimento e é única por fornecedor (409 SUPPLIER_STATE_REGISTRATION_DUPLICATE_CONFLICT). IE de substituto tributário em UF onde não há estabelecimento fica fora da v1. O erro clássico é uma coluna de texto que recebe "ISENTO" digitado de sete jeitos.
caepfvarchar(14)?opcSó em RuralProducer e Individual: o CAEPF da propriedade ou da atividade, quando existe. Único por tenant onde não nulo.
municipalRegistration / municipalRegistrationCityCodestring(20) / código IBGEopcNecessária para prestador de serviço emitir NFS-e.
isPrimaryboolobrigExatamente um por fornecedor, de qualquer tipo de pessoa. É o padrão em pedidos quando nenhum outro é escolhido.
paymentTerms / currency / defaultIncotermstring(40) / char(3) → Currency / char(3)?opcTermos comerciais negociados. defaultIncoterm só para Foreign — o preço só aceita incoterm com fornecedor estrangeiro (ver o Item). O prazo é do Nexio; o cálculo do vencimento e dos encargos é do ERP.
receiptToleranceobjopcPercentuais de over e under delivery, dias de antecipação e atraso aceitos, e a política de entrega antecipada (Warn | Block, default Warn). É o nível mais geral da precedência, e cada campo é herdado pelos níveis abaixo quando eles não o preenchem. Detalhado na Unidade de Medida.

Armadilha de importação: o Excel converte 3E5… em notação científica e come zeros à esquerda. O importador precisa forçar a coluna de CNPJ como texto. E a API deve expor CNPJ como string desde o dia 1, mesmo enquanto for numérico — trocar tipo em API pública depois é caro.

Domínio

Endereços e contatos

Propósito de endereço é flag, não enum

A Oracle usa AddressPurposeOrderingFlag, AddressPurposeRemitToFlag e AddressPurposeRFQOrBiddingFlag — booleanos independentes. Um endereço pode ser simultaneamente de pedido e de cobrança; um enum "tipo de endereço" obrigaria a cadastrar o mesmo endereço duas vezes. O Nexio usa as mesmas flags mais purposeShipping e fiscal.

Contato tem papel; a Oracle não tem e faz falta

O modelo da Oracle só traz AdministrativeContactFlag e deixa o papel funcional emergir da associação contato×endereço. O Nexio precisa de roles[] — Commercial, Tax, Finance, Technical, Quality, PortalAdmin — porque precisa saber para quem enviar o RFQ e para quem enviar o pedido, que raramente são a mesma pessoa. Exatamente um contato ativo tem o papel PortalAdmin — é papel em roles[], não campo à parte, e faz parte da cadeia de reserva do aviso bancário, ao lado de um contato Commercial designado e do contato designado do estabelecimento principal (RN-FOR-34); os demais contatos Commercial são livres e ficam fora da cadeia.

Contato e credencial são entidades separadas

SupplierContact 1:0..1 PortalUser. O contato é dado cadastral e pode existir sem login; o usuário do portal tem status de conta, escopo de acesso e MFA. Fundir os dois faz com que desativar um contato apague um acesso, e vice-versa.

Telefone e e-mail carregam quando e por quem foram gravados

phoneSource (Manual | RegistryLookup | Import | InitialLoad), phoneRecordedAt e phoneRecordedByUserId — e os equivalentes de mobile e email — são gravados pelo sistema toda vez que o valor muda, nunca informados por quem edita; noticeChainSince e noticeChainProposalId gravam quando e por qual proposta o contato entrou em Finance ou numa posição da cadeia (noticeChainSlot), inclusive por reativação, e o relógio de confiança do número conta do mais tarde entre as duas datas; quando o valor entra por alteração de contato, phoneChangeProposalId e equivalentes apontam a proposta, e com ela quem propôs, confirmou ou aprovou. É deles que sai o telefone confiável do callback — só de contato ativo Finance ou da cadeia de reserva (RN-FOR-29) — e a separação entre as pessoas ligadas ao número e quem liga para ele. Contato que recebe o aviso bancário ou atende o callback muda por alteração protegida (RN-FOR-34).

EntidadeCampos
SupplierAddresslabel, street, number, complement, district, cityCode (IBGE), state, postalCode, country, landmark, phone, email, purposeHeadquarters, purposeOrdering, purposeShipping, purposeRemitTo, purposeRfq, purposeTax, supplierEstablishmentId?, status, inactiveOn
SupplierContactfirstName, lastName, jobTitle, email, phone, mobile, roles[], noticeChainSlot?, addressIds[], supplierEstablishmentId?, status, inactiveOn, emailRecordedAt, emailRecordedByUserId, emailChangeProposalId?, phoneSource, phoneRecordedAt, phoneRecordedByUserId, phoneChangeProposalId?, mobileSource, mobileRecordedAt, mobileRecordedByUserId, mobileChangeProposalId?, emailBouncedAt?, noticeChainSince?, noticeChainProposalId?
PortalUsercontactId, login, accountStatus, dataAccessScope, mfaEnabled, lastAccessOn

Domínio · FornecedorDocumento

Documentos

Tipo de documento é catálogo configurável por tenant, não enum de código. Campo fixo por tipo (fgtsCertificateUrl, fgtsExpiresOn) não escala e obriga migração para cada novo tipo.

CampoRegra
documentTypeIdCatálogo do tenant. Cada tipo declara: nível (raiz ou estabelecimento), se tem vencimento, validade padrão, se é exigido por categoria, e a política de vencimento.
scopeSupplier ou Establishment — herdado do tipo.
supplierEstablishmentIdcond Obrigatório quando scope = Establishment, proibido quando scope = Supplier (400 SUPPLIER_DOCUMENT_ESTABLISHMENT_REQUIRED). É o que distingue o alvará da filial da Bahia do alvará da filial de Minas — sem ele, três alvarás de três filiais são três linhas iguais, e o pacote exigido não sabe qual falta. Ver RN-FOR-25.
number, issuer, issuedOn, expiresOnVencimento nulo = documento sem validade (contrato social).
storedFileId→ GrydFiles, perfil nexio.supplier-document. Hash, antivírus, retenção e URL pré-assinada são do módulo de arquivo; o SupplierDocument cria a sua FileReference com ownerScope = "nexio.supplier-document" e a libera quando o documento é substituído. Não é Attachment: tem número, órgão, vigência e status derivado da data — a regra de corte da spec de Anexo.
statusgerado Valid | Expiring | Expired | Waived — derivado da data, com janela de "a vencer" configurável. Nunca gravado à mão.
confirmedBy / confirmedOnQuem, do lado do comprador, conferiu o documento. Diferente de quem subiu.
waivedBy / waiverReasonDispensa é decisão registrada, não campo em branco.

Catálogo-semente de tipos, com o nível certo

DocumentoEmissorValidadeNível
Contrato / estatuto socialJunta comercialsem validaderaiz
CND / CPEN federalRFB + PGFN (conjunta)180 diasraiz
CRF do FGTSCaixa Econômica Federal30 dias — a mais curta do pacote, porque o recolhimento é mensalraiz
CNDTJustiça do Trabalho / TST180 diasraiz
Certidão estadualSEFAZ / PGE da UF30 a 180 dias, variaestabelecimento
Certidão municipalPrefeitura30 a 90 dias, variaestabelecimento
Falência / recuperação judicialCartório distribuidor da comarca da sede30 a 180 dias · pagaraiz
Alvará de funcionamentoPrefeiturageralmente anualestabelecimento
Licença ambiental (LP/LI/LO)Órgão estadual ou IBAMAanos, por licençaestabelecimento
Licenças setoriais (ANVISA AFE, MAPA, ANTT, ANP)Órgão setorialvariaestabelecimento · por categoria
ISO 9001 / 14001 / 45001Organismo acreditadociclo de 3 anosestabelecimento
Apólices (RC geral, RC profissional, performance bond)Seguradoravigência da apóliceraiz · por categoria
Código de conduta assinadoo próprio tenantconfigurávelraiz

Seis dos treze tipos-semente são por estabelecimento — certidão estadual, certidão municipal, alvará, licença ambiental, licenças setoriais e certificação ISO —, e as licenças setoriais somam o eixo de categoria. Falência e recuperação judicial são da pessoa jurídica, e ficam na raiz. É por isso que supplierEstablishmentId existe na linha: o pacote exigido é resolvido por estabelecimento ativo, e GET /suppliers/{id}/document-requirements devolve o que falta com o alvo, não uma lista plana. As três certidões federais de vigilância contínua — CND/CPEN, CRF do FGTS e CNDT — não têm consulta automatizada na v1 e são entrada manual com vigência (RN-FOR-26); a consulta automática é v2, pelo gancho de provedor plugável.

Documento vencido não deve apagar o fornecedor do mapa. Nenhum dos produtos pesquisados bloqueia automaticamente o cadastro ao vencer um documento — o padrão real é sinalizar e rotear para decisão humana. No Nexio, a política é por tipo de documento e graduada: avisar, exigir justificativa na aprovação do pedido, ou bloquear a emissão de novo pedido. Bloqueio silencioso trava a operação e gera o workaround clássico — o comprador cadastra um fornecedor duplicado para contornar, o que alimenta o problema da antiduplicidade.

Domínio · FornecedorVerificacao

Verificações em fonte oficial

Entidade append-only: cada consulta gera um registro novo, com fonte, data, resultado e evidência. Sem a data da consulta, a flag é inauditável — o par flag + fonte + data é o que a Oracle faz com OnOFACListFlag e OFACSources.

FonteO que devolveAutomatizávelUso
Receita — CNPJRazão social, fantasia, endereço, telefone, CNAEs, porte, situação, identificador matriz/filial, sóciosSim — pelo gancho de provedor; na v1, espelho dos dados abertos, com a data de referência da base gravada na verificaçãoAutopreenchimento no cadastro e revalidação periódica da situação
Receita — Simples/MEIOpção e datasSim (dados abertos)Regime tributário
Portal da Transparência — CEIS, CNEP, CEPIM, acordos de leniênciaSanções por CPF/CNPJSim — API pública e gratuita, com token; limites de 400 req/min das 06h às 24h e 700 req/min das 00h às 06hAlerta reputacional. Não bloqueia — ver princípio 5
TCU — consulta consolidada de pessoa jurídicaLicitantes inidôneos (TCU), CNIA do CNJ (improbidade), CEIS e CNEP numa consulta sóSim — acesso programático a confirmar no spike do provedorAlerta reputacional, como as demais sanções
Lista suja do trabalho escravo (MTE)Empregadores autuadosSim — publicação semestral (abril e outubro), por downloadAlerta bloqueante por política do tenant
OFAC / SDNSanções dos EUASim — arquivos para downloadRelevante em fornecedor estrangeiro
SINTEGRA / SEFAZ estadualSituação da inscrição estadualParcial — 27 portais, cobertura por API comercialValidação de IE
ERP do tenant — destino de pagamentoConta ativa do fornecedor no ERPSim — pelo adaptador de ERP, quando ele expõe a leituraConferência diária com a conta do Nexio — ver RN-FOR-32
DICT (via PSP) / consulta de boletoTitular da chave PIX ou do boletoSim, por parceiroValidação de titularidade bancária — ver § bancário
CND / CPEN federal (RFB + PGFN)Regularidade fiscal federalNão na v1 — emissão por formulário com CAPTCHA, sem API públicaentrada manual SupplierDocument com número, emissão e vencimento; validade 180 dias
CRF do FGTS (Caixa)Regularidade do FGTSNão na v1 — sem API públicaentrada manual A mais curta do pacote: 30 dias. É a que mais vence, e a que mais precisa do aviso antecipado
CNDT (TST)Débitos trabalhistasNão na v1 — sem API públicaentrada manual Validade 180 dias

Um gancho de provedor, e a defasagem declarada

Quase todas as APIs gratuitas de CNPJ derivam do mesmo dump de dados abertos da Receita e herdam a latência dele — semanas. A consulta ao CNPJ fica atrás de um gancho de provedor plugável, o mesmo que servirá às certidões e que a Empresa também consome para a situação dos estabelecimentos compradores, e o provedor da v1 é o espelho dos dados abertos: bom e barato para autopreenchimento, busca e varredura. A defasagem não some, então é declarada: toda SupplierVerification grava fonte, data da consulta e data de referência da base, e a homologação e o pedido mostram "situação em dd/mm". Comprovante de inscrição e situação cadastral registrado por quem tem verify:suppliers vale como verificação manual, com a mesma gravação. Onde a defasagem não for aceitável, troca-se o provedor — um serviço comercial com SLA —, não a spec.

O autopreenchimento é a maior alavanca de conversão do onboarding

Razão social, fantasia, endereço, CNAEs, porte, situação, sócios e Simples estão todos disponíveis a partir do CNPJ. Isso reduz um formulário de trinta campos para cerca de oito digitados. É, na prática, o principal diferencial dos SRMs brasileiros de homologação, e é replicável.

A varredura roda em lote, não só na homologação

Com uma API pública, gratuita e com limite generoso cobrindo quatro cadastros de integridade, não há razão para consultar apenas no onboarding. Um job periódico varre a base inteira e abre alerta quando algo muda — é o melhor custo-benefício de todo o pacote de compliance. A varredura cobre situação cadastral e sanção, não certidão. Todo estabelecimento ativo é reconsultado pelo menos a cada 30 dias, e verificação com mais de 45 dias não autoriza pedido novo (RN-FOR-24) — provedor fora do ar vira alerta muito antes de virar pedido travado.

Três das certidões que o produto promete vigiar não têm fonte, e isso está escrito

CND/CPEN, CRF do FGTS e CNDT são emitidas por formulário, com CAPTCHA, sem API pública. Na v1 elas são documento de entrada manual com vigência — o status continua derivado da data, o upload continua indo ao arquivo, e o que muda é que ninguém as consulta sozinho. O aviso passa a ser antecipado: 30, 15 e 5 dias antes do vencimento, e não só depois — que é o comportamento de hoje e é inútil, porque a essa altura a política de documento vencido já travou o pedido. A consulta automática é v2, por provedor plugável. Prometer varredura que não existe é pior do que não prometer: o comprador confia e o vencimento passa.

Processo

Homologação

CampoRegra
supplierIdHomologação é da entidade jurídica; documentos de estabelecimento são conferidos dentro dela.
scopeCategoryIdsNós da árvore de categorias. Um fornecedor pode estar homologado em Serviços de Limpeza e não em Produtos Químicos.
questionnaireId / answersQuestionário modular reutilizável entre processos, não template por projeto.
riskTierLow | Medium | High | Critical. Define o pacote de documentos exigido e a periodicidade da revalidação.
outcomeApproved | ApprovedWithFindings | Rejected. A opção do meio é o que o mercado brasileiro efetivamente usa e o que evita reprovar por um documento faltante.
findings[]Cada ressalva com descrição, prazo e responsável. Ressalva sem prazo é ressalva esquecida.
validTo / nextReviewOnCríticos tipicamente anual; demais, bienal.
approvalRequestId · approvals[]A instância do motor no processo SUPPLIER, e a leitura das tarefas dela — área (o rótulo do alvo), aprovador, decisão, data. Em paralelo — jurídico, financeiro, técnico e qualidade revisam ao mesmo tempo, não em cadeia: é o nível Panel do motor, um aprovador de cada alvo. A política padrão semeada é um nível só (PermissionHolder(update:supplier-qualifications)); o tenant troca pelo painel de quatro áreas quando quiser. approvals[] não é gravado aqui — é projeção da instância.

Requalificação preserva o escopo da qualificação anterior — mesmas categorias, mesma faixa de risco. Recomeçar do zero com escopo diferente é como uma homologação vencida vira um fornecedor que ninguém sabe se pode usar.

Quem decide e quem executa. Submeter a qualificação abre a instância SUPPLIER com scopeCategoryIds e riskTier como critérios — "risco Critical exige jurídico" é política, não código. Quando a instância termina em Approved, o Fornecedor grava outcome (com ApprovedWithFindings quando alguma tarefa aprovou com ressalva), findings[], validTo, e promove o fornecedor a SpendAuthorized (RN-FOR-04). Rejeição grava Rejected com a quádrupla de motivo, uso SupplierReject. Quem conduz a qualificação — questionário, documentos — não decide: a RN-AP-08 o remove das tarefas.

Segurança

Dados bancários

A fraude não precisa que você pague — precisa que você armazene o dado que alguém a jusante vai usar. O Nexio é a fonte da verdade da conta do fornecedor: guarda, versiona, aplica a proposta aprovada e envia a conta ao ERP — e confere todo dia se o ERP continua pagando na mesma conta (RN-FOR-32). Por isso esta seção inteira é requisito, não sugestão. No Brasil a jurisprudência tende a não responsabilizar o banco quando o boleto foi emitido fora da plataforma bancária: a perda fica com quem pagou.

Campos

CampoRegra
accountKindDomestic | International. Discrimina o bloco de campos — doméstico usa ISPB, agência, conta e chave PIX; internacional usa IBAN, SWIFT/BIC, país e banco intermediário. Campo do bloco errado responde 400 SUPPLIER_FIELD_NOT_APPLICABLE nomeando campo e bloco. Ver RN-FOR-27.
supplierEstablishmentIdopc Nulo = a conta vale para todos os estabelecimentos do fornecedor; preenchido = só para aquele. Pagamento a um estabelecimento usa a conta dele e, sem ela, a conta de escopo nulo.
currencyobrig char(3) → Currency, ISO 4217. Domestic é sempre BRL; International declara a moeda da conta.
isDefaultobrig Exatamente uma conta padrão vigente por fornecedor e escopo de estabelecimento. Trocar a padrão muda o destino do pagamento, então é proposta (RN-FOR-35).
ispb / compeCodebloco doméstico Guardar o ISPB de 8 dígitos como chave — é o identificador moderno no SFN. O COMPE de 3 dígitos fica como conveniência de exibição.
branchNumber / branchCheckDigit / accountNumber / accountCheckDigitFormatos variam por banco; não existe validação universal.
accountTypeChecking | Savings | Payment. Conta de pagamento cobre fintechs.
holderName / holderTaxIdTitular diferente do fornecedor é recusado na submissão (422 BANK_HOLDER_MISMATCH_UNPROCESSABLE). A comparação é por tipo de pessoa: raiz do CNPJ em Company — a filial recebe na conta da matriz —; documento inteiro em MEI (CNPJ do MEI ou CPF do titular), Individual e RuralProducer. Só Foreign, sem documento brasileiro, segue com veredito de nome e, não conferindo, com a flag "titular ≠ fornecedor", controladoria e comprovante. Ver RN-FOR-13.
pixKeyType / pixKeyCNPJ | CPF | Email | Phone | Random. Ver a tabela de risco abaixo.
validFrom / validToVersionamento. Nunca UPDATE na linha — sempre nova versão, com autor e justificativa.
holderVerificationResultado da consulta ao DICT ou ao boleto: documento retornado, comparação com o do fornecedor, veredito e carimbo de tempo.
usableFromcarência Data e hora a partir das quais a conta é destino de pagamento legítimo. Gravada pelo contrato de desfecho quando a instância BANK_ACCOUNT_CHANGE termina em Approved: decidedAt + bankChangeGraceHours (configuração do tenant, 24 a 72 h, padrão 48). Conta com usableFrom no futuro não entra no pacote enviado ao ERP e responde 409 BANK_ACCOUNT_NOT_USABLE_YET_CONFLICT a quem a pedir como destino. Nunca é editada por PUT, nunca anda para trás, e não existe rota de antecipação — a carência é o controle. Ver RN-FOR-22.
contestedAtgerado Preenchido quando a proposta que criou esta versão é contestada depois de aplicada (RN-FOR-30). Conta com contestedAt não é destino de pagamento — não entra no pacote do ERP e responde 409 BANK_ACCOUNT_CONTESTED_CONFLICT a quem a pedir —, e não volta a ser: o caminho é proposta nova. A versão anterior não é reaberta sozinha.
iban / swiftBic / bankCountryCode / bankNamebloco internacional Obrigatórios quando accountKind = International. iban validado por formato e dígito ISO 13616 quando o país usa IBAN; swiftBic em 8 ou 11 caracteres, ISO 9362; bankCountryCode em ISO 3166-1 alfa-2. Onde não há IBAN (EUA, Canadá), accountNumber e o código de compensação local voltam a valer dentro deste bloco, com routingCodeType = ABA | TransitNumber | SortCode | Other.
intermediaryBankSwiftBic / intermediaryBankNameopc Banco intermediário, quando o correspondente exige. Ausência não é erro; presença sem accountKind = International é.

Chave PIX e risco

TipoCarrega identidade?Leitura
CNPJSim, diretamentemenor risco Auto-verificável contra o cadastro. É a chave a preferir e a sugerir ao fornecedor.
CPFSimalerta Para fornecedor pessoa jurídica, chave CPF é sinal de alerta.
Email / PhoneNãoalerta Exige resolução no DICT para saber de quem é.
Aleatória (EVP)Não carrega nenhuma informaçãomaior risco É impossível saber o titular olhando. Aceitar sem resolver no DICT é aceitar um destino de pagamento anônimo.

O mecanismo: proposta de alteração

ControleComo funciona
Proposta, não ediçãoA alteração vai para BankAccountChangeProposal. O registro vivo não muda até a aprovação. O aprovador vê atual vs. proposto lado a lado — não se aprova um registro, aprova-se uma mudança.
Núcleo protegido — não configurávelTodo campo de SupplierBankAccount que diz para onde o dinheiro vai — banco (ISPB/COMPE), agência, conta e dígitos, tipo de conta, chave PIX, IBAN, SWIFT/BIC, país, banco intermediário, titular — e o e-mail e o telefone de todo contato com papel Finance, que são o canal do aviso e a origem do callback. O núcleo muda só por proposta, e nenhuma configuração, papel ou modo de importação o tira dessa regra (RN-FOR-28). Proteger o destino do dinheiro sem proteger o canal do aviso não protege nada: quem reescreve os contatos plantando o próprio endereço recebe, ele mesmo, o aviso da troca que vai propor em seguida. Ver RN-FOR-21.
Campos protegidos por configuraçãoFora do núcleo, o tenant pode acrescentar campos que também só mudam por proposta — a razão social é o caso típico. A lista só acrescenta; nunca retira campo do núcleo. Mudá-la é ato de controle, com registro do ato e aviso obrigatório a quem tem approve:supplier-banks (RN-FOR-28).
Mudança de canal também é propostaAlterar e-mail ou telefone de contato Finance ou da cadeia de reserva — PortalAdmin, Commercial designado e contato designado do estabelecimento principal —, por tela, por PUT /suppliers/{id}/contacts ou por importação, responde 409 SUPPLIER_CONTACT_PROTECTED_FIELD_CONFLICT e exige POST /suppliers/{id}/contacts/change-proposals, que cria a proposta em Draft na mesma entidade da proposta bancária. O changeKind sai do papel: Finance é NoticeContact e abre a mesma instância BANK_ACCOUNT_CHANGE — mesmo motor, mesma separação, mesmo aviso no canal anterior; a cadeia é ChainContact, confirmada por segunda pessoa depois do aviso entregue e do callback. Sem telefone confiável, a ligação para o número que já se conhecia dá lugar à instância com a controladoria, ao pedido de troca assinado pelo fornecedor (SIGNED_CONTACT_CHANGE_REQUEST), anexado antes da submissão e gravado no desfecho com quem anexou, quem decidiu, data e hora — o sistema exige o anexo, não confere o documento —, e a 7 dias de carência; sem o pedido assinado, a troca não é submetida (422 SUPPLIER_CONTACT_CHANGE_NO_TRUSTED_PHONE_UNPROCESSABLE). Aplicada, a mudança tem carência e aviso ao endereço anterior com link de contestação; contestada, trava as propostas de conta até nova troca decidida com a controladoria — e volta atrás, salvo quando veio de canal já comprometido ou de pedido assinado, caso em que fica suspensa e é a controladoria que decide qual valor vale (RN-FOR-38). Contato livre só existe antes da aprovação do cadastro; depois, até o primeiro contato do aviso é ChainContact, confirmado por callback para o telefone da consulta ao provedor. Os demais contatos Commercial ficam livres e fora da cadeia. Ver RN-FOR-34 e RN-FOR-38.
Quem decideA proposta submetida abre uma instância do motor, processo BANK_ACCOUNT_CHANGE, com as flags calculadas na submissão: "titular ≠ fornecedor" (só Foreign, RN-FOR-13), "chave PIX não verificada", noTrustedPhone, previousNoticeUndeliverable e contestedChannel. A semente normativa desse processo vive numa página só, o Fluxo de Aprovação, e esta página não a repete. O que o Fornecedor precisa saber dela: o processo é sem valor avaliado; quem decide — o quórum e o complementar da controladoria — são pessoas com identidade verificada, distintas entre si e diferentes do proponente (RN-FOR-36); não há delegação, reatribuição nem escalonamento; e, sem pessoas elegíveis suficientes, a instância fica parada com alerta ao administrador — nunca cai em reserva. Na decisão que concluiria a instância, o motor invoca o contrato de desfecho do Fornecedor, que confere as guardas da RN-FOR-23, da RN-FOR-29, da RN-FOR-35, da RN-FOR-36, da RN-FOR-40 e da RN-FOR-41 e, passando, aplica a proposta ao registro vivo e grava usableFrom na mesma transação; não passando, devolve Refused com o código, a decisão não é gravada e a tarefa continua ativa.
Sem valor avaliadoO processo não mede valor, e faixa por valor não entra na política dele. A troca de conta de um fornecedor pequeno desvia o próximo pagamento tanto quanto a de um grande — e o fornecedor novo, que não tem histórico de compra, é justamente o mais atacado. Um controle que afrouxa conforme o valor ensina o fraudador a escolher o alvo.
Aprovador ≠ solicitanteObrigatório, sem exceção de urgência — garantido pela RN-AP-08 do motor, que remove o solicitante de toda tarefa da própria instância. Idealmente o aprovador não é de quem fez a compra.
Mesma regra na tela, na API e na importaçãoA importação tem dois modos para campo protegido, e só dois: Propose (padrão) — cada fornecedor com alteração vira uma proposta em rascunho, sem aviso, token nem instância, com quem importou como proponente; aviso, janela, callback e decisão só começam na submissão, que é do proponente e exige a titularidade como na tela (RN-FOR-35) — ou Reject — a linha é recusada com 409 BANK_CHANGE_REQUIRES_PROPOSAL_CONFLICT e, pela regra de importação tudo ou nada, a carga não grava. Não existe modo que aplique sem aprovação. É aqui que a maioria das implementações vaza. A única entrada de conta sem proposta decidida é a carga inicial de implantação, com as travas da RN-FOR-31.
Verificação de titularidadeResolver a chave PIX no DICT ou consultar o beneficiário do boleto, comparar com o CNPJ do fornecedor e gravar o veredito. Este controle não existe nos concorrentes globais no Brasil.
Carência antes do primeiro usoÉ o campo usableFrom, não uma frase: 24 a 72 h entre a decisão e a liberação para pagamento, com a invariante "conta em carência não sai no pacote do ERP" escrita na RN-FOR-22. Sem campo, a carência não existe — o que existe é a intenção de tê-la.
Janela mínima entre o aviso e a primeira decisãoNenhuma tarefa da instância é ativada antes de noticeSentAt + minNoticeHours (configuração do tenant, mínimo 12 h, padrão 24): o Fornecedor entrega esse instante ao motor pelo gancho genérico activationNotBefore, e quem segura a ativação é o motor. E-mail devolvido não inicia a janela: ela conta do último aviso que saiu sem devolução. Aviso disparado e proposta aprovada no mesmo minuto é aviso decorativo: o fornecedor legítimo precisa de tempo de reagir antes de a conta trocar, não depois. Ver RN-FOR-23.
Aviso no canal anterior — só por e-mail na v1O contato Finance é avisado antes da mudança, por e-mail. Não há SMS nem WhatsApp na v1: a plataforma entrega Email, Push e InApp, e os dois canais que faltam são os mais atacados — clonagem de número e SIM swap. O telefone continua cadastrado para o callback, que é obrigatório e cobre o cenário em que o e-mail do fornecedor está comprometido. O resolvedor Previous lê o contato vigente antes da alteração proposta — na proposta bancária e na de canal —, o que fecha o ataque em dois passos. Consentimento do contato não é condição do aviso: a base é prevenção a fraude. O aviso não pode deixar de sair da empresa: na falta de contato Finance com e-mail, a cadeia cai para PortalAdmin, depois o Commercial designado, depois o contato designado do estabelecimento principal — e, se nenhum e-mail fora do tenant existir, a proposta não abre (422 BANK_CHANGE_NO_EXTERNAL_NOTICE_CHANNEL_UNPROCESSABLE). O administrador do tenant recebe cópia; ele nunca é o destinatário no lugar do fornecedor. O aviso leva o link de contestação.
Callback de saída, para telefone confiávelCom telefone confiável, a proposta só conclui com um callback Confirmed: ligação de saída, feita por alguém com approve:supplier-banks que não é o proponente nem pessoa ligada ao número — quem o gravou, propôs, confirmou ou aprovou —, para um telefone confiável — número de contato ativo Finance ou da cadeia de reserva com 30 dias contados do mais tarde entre a gravação do número e a entrada do contato em Finance ou na cadeia, ou devolvido pela consulta ao CNPJ feita pelo provedor, com 30 dias quando mudou desde a consulta anterior —, falando com a pessoa responsável no fornecedor. A evidência grava número, origem, quem ligou, quando, com quem falou, resultado e o hash dos dados da proposta. Número recém-cadastrado — por colega honesto ou pelo fraudador — não serve, contato técnico, de qualidade ou comercial não designado não é fonte, e comprovante manual nunca é fonte de telefone. Sem telefone confiável — e só depois de uma consulta nova ao provedor —, o que resta é o passo complementar da controladoria com prova documental — titularidade na proposta de conta; pedido assinado e 7 dias de carência na troca de canal —; e número que só falta por estar ligado ao proponente recusa a submissão. Denied contesta a proposta. Ver RN-FOR-29.
Rascunho, titularidade e imutabilidadeA proposta nasce em Draft e só é submetida com o comprovante de titularidade da conta nova anexado e liberado pelo antivírus. Submetida, não muda mais: BANK_ACCOUNT_CHANGE não tem devolução, e corrigir é rejeitar e abrir proposta nova. Callback e titularidade valem só para o hash dos dados com que foram registrados — sem isso, a ligação que confirmou a conta X seguiria valendo para a conta Y. Ver RN-FOR-35.
Contestação — "não fui eu"O aviso ao canal anterior e o aviso de aprovação levam um link de contestação de uso único, sem login, e a instrução de ligar para o comprador por um número que o fornecedor já conhece. Contestar — pelo link, pela equipe interna que recebe a ligação, ou pelo callback com Denied — cancela a instância em andamento ou, se a proposta já foi aplicada, tira a conta nova do caminho do pagamento; mudança de contato aplicada e contestada volta ao valor anterior e trava as propostas de conta (RN-FOR-38). A proposta contestada é final: troca legítima recomeça por proposta nova. Ver RN-FOR-30.
Aviso da aprovação também ao canal anteriorQuando a proposta é aplicada — de conta ou de contato —, o aviso vai à controladoria e ao mesmo canal anterior, com a data de usableFrom e o link de contestação: a carência só serve ao fornecedor legítimo se ele souber que ela começou.
Carga inicial de implantaçãoA única entrada de conta sem instância do motor, e é exceção declarada: janela única por tenant, só para fornecedor que ainda não tem conta nem proposta aberta, envio por uma pessoa e confirmação por outra sobre o mesmo arquivo (dupla custódia), titularidade ou callback por conta carregada, contatos Finance no mesmo lote, carência aplicada e evento próprio. Fechada a janela, não reabre. Ver RN-FOR-31.
Conferência com o ERPO golpe não pode só mudar de lugar: se a conta continua editável no ERP, trocar lá é trocar sem nenhum destes controles. A conferência diária compara a conta que o ERP usa para pagar com a conta utilizável no Nexio e alerta a divergência. Ver RN-FOR-32.
Alertas de padrãoMesma conta em dois fornecedores diferentes; conta em UF descolada do domicílio; mudança pouco antes de um pagamento grande.
Trilha imutávelValor anterior, novo, quem, quando, de qual IP e por qual canal. Em fraude consumada, é isso que determina responsabilidade.

A proposta — os campos que os controles leem

CampoRegra
changeKindBankAccount | NoticeContact | ChainContact. As duas primeiras abrem a instância BANK_ACCOUNT_CHANGE e passam pelos mesmos controles; ChainContact é a alteração protegida dos contatos da cadeia de reserva, confirmada por segunda pessoa — e abre a instância quando não há telefone confiável ou enquanto o fornecedor tiver propostas de conta travadas (RN-FOR-34, RN-FOR-38). Nas propostas de contato, o tipo é calculado pelos papéis e pela posição do contato — e o primeiro contato do aviso de cadastro aprovado é sempre ChainContact —, nunca declarado.
origin / initialLoadBatchIdStandard | InitialLoad. InitialLoad não abre instância, não emite aviso nem token de contestação e só existe dentro da carga inicial, agrupada pelo lote (RN-FOR-31). changeKind = ChainContact com telefone confiável e fora de trava também não abre instância: é confirmada por segunda pessoa (RN-FOR-34).
statusDraft | Open | Applied | Rejected | Cancelled | Contested. Draft até a submissão — editável e descartável só pelo proponente, sem aviso nem instância; Open depois de submetida (ou, em carga inicial, até a confirmação); Applied quando o desfecho aplica; Rejected e Cancelled pelo motor, pela confirmação de contato ou pelo fechamento da janela de carga; Contested pela RN-FOR-30 e pela RN-FOR-38; Cancelled também pela trava da RN-FOR-38. Rejected, Cancelled e Contested são finais; Applied só sai para Contested.
targetBankAccountId / deactivateA conta que muda. Nulo inclui conta nova; preenchido substitui a versão vigente daquela conta; deactivate = true a encerra.
submittedAt / dataHashGravados na submissão. dataHash cobre os dados propostos — na proposta que põe um contato em Finance ou na cadeia, também o e-mail e os telefones dele — e os identificadores do comprovante de titularidade ou do pedido assinado; depois dele, nada na proposta muda (RN-FOR-35).
noTrustedPhone / previousNoticeUndeliverable / contestedChannelFlags calculadas pelo sistema na submissão e enviadas ao motor: proposta — de conta ou de canal — sem telefone confiável depois da consulta nova ao provedor (RN-FOR-29, RN-FOR-34); correção de e-mail cujo aviso anterior foi devolvido (RN-FOR-23); troca de canal de fornecedor com propostas de conta travadas (RN-FOR-38). As três acionam o complementar da controladoria.
confirmedByUserId / confirmedAtQuem confirmou a alteração ChainContact e quando (RN-FOR-34). Com o proponente, o autor do callback e quem decidiu na instância, forma o conjunto de pessoas ligadas ao valor aplicado (RN-FOR-29).
usableFromSó nas propostas de contato: aplicação + bankChangeGraceHours, ou aplicação + 7 dias com noTrustedPhone. Até lá, o aviso bancário do fornecedor vai ao valor anterior; o token do aviso de aplicação vale até 30 dias depois (RN-FOR-34, RN-FOR-38).
proposedByUserId / createdAtQuem propôs e quando. É a referência de toda guarda "pessoa diferente do proponente" desta seção.
noticeSentAt / noticeBouncedAtnoticeSentAt grava o aceite do aviso pelo provedor de e-mail; a devolução grava noticeBouncedAt, e o envio seguinte pela cadeia regrava noticeSentAt. A janela conta do último envio sem devolução (RN-FOR-23).
callbackPhone / callbackPhoneSource / callbackSourceId / callbackByUserId / callbackAt / callbackSpokeWith / callbackResult / callbackDataHashA evidência do callback, gravada uma vez. callbackPhoneSource = AgedContactPhone | RegistryLookup; callbackSourceId é o contato ou a verificação de onde o número saiu; callbackResult = Confirmed | Denied; callbackDataHash = o dataHash da proposta no registro. Tentativa sem atendimento não grava campo — vai à trilha (RN-FOR-29).
signedRequestSó em proposta de canal com noTrustedPhone: o rastro do pedido assinado, gravado pelo desfecho — identificador do anexo SIGNED_CONTACT_CHANGE_REQUEST, quem anexou e quando, quem decidiu e quando. O sistema não confere o documento; sem o anexo liberado, o desfecho recusa (RN-FOR-40).
contestedAt / contestChannel / contestNotecontestChannel = Link | Internal | Callback. Preenchidos pela contestação (RN-FOR-30).
contestTokenHash / contestTokenExpiresAt / contestTokenUsedAtSó o hash do token é guardado; o token em claro existe apenas no e-mail. Cada e-mail que leva o link emite token novo e invalida o anterior.

Domínio · FornecedorCategoria

Categorias fornecidas

Relação N:N com CategoryNode, com entidade associativa própria — o mesmo desenho do Products and Services da Oracle. Duas semânticas que precisam ficar separadas:

Declarativa

SupplierCategory. O que o fornecedor diz — ou foi aprovado — a fornecer. Origem: declaração do comprador no cadastro, mais aprovação. Uso: descoberta — montar a lista de convidados de um RFQ, busca, segmentação. Não bloqueia nada. Guarda a origem (declarado ou homologado) e quem informou.

Autorizativa

SupplierQualification.scopeCategoryIds vigente. O que ele pode de fato ter comprado é o resultado de uma consulta — supplierId × categoryNode, casando por prefixo de path e respeitando validTo —, não de um estado do relacionamento. É o papel da Approved Supplier List da Oracle. ItemSupplier.status continua sendo trava por item onde a relação existe, e nunca é o gate: item sem ItemSupplier ficaria sem nenhum. Ver RN-FOR-24.

Fundir as duas transforma um campo declarado sem verificação em controle de compliance. A documentação da Oracle é explícita: Products and Services serve para identificar quem convidar para negociações — quem restringe a compra é a ASL.

Ponte com o Catálogo

Item × Fornecedor

Especificado em Cadastro de Item; aqui ficam a chave e as decisões que dependem do fornecedor. A parte de unidade de compra, fator de conversão e preço por quantidade está detalhada no documento de Unidade de Medida.

A relação e o preço são duas entidades, e a UF é dimensão de preço

O análogo exato é a ASL da Oracle, chaveada em item ou categoria × organização de entrega × fornecedor × site, com atributos que são quase os mesmos do ItemSupplier: unidade de compra, país de origem, quantidade mínima e múltiplo de lote. No Nexio o par é ItemSupplier — a relação de fornecimento, chaveada em três partes (itemId + supplierId + supplierEstablishmentId?) e dona de status, isPreferred/priority, tolerâncias, reviewByDate e das unidades de compra, que são a filha ItemSupplierUom — mais ItemSupplierPrice, a versão de preço, filha e append-only, chaveada por itemSupplierId + validFrom + shipToStateCode? + companyId? + freightTerms?. A vigência e a UF de destino saíram da chave da relação e foram para a do preço, que é o movimento inteiro. A UF fica no preço porque não é dimensão de relacionamento: com ela na relação, um fornecedor com preço nacional mais uma exceção de SP viraria duas relações para um único relacionamento, sem resposta para qual delas carrega o status — e mudar o endereço de entrega de uma requisição mudaria de relacionamento de fornecimento, porque a FK da linha aponta para a relação. Mudar onde se recebe muda o preço, nunca o fornecedor. Estabelecimento nulo significa "vale para todos os estabelecimentos" — dá o comportamento da Oracle sem obrigar todo cliente a modelar filiais. É o info record × condition record do SAP e o ASL × price break do Oracle: reajustar preço deixa de duplicar a relação, "máximo dez preferidos por item" volta a contar relações, e o DELETE "só se nunca usado" volta a ser decidível. Esta página descreve a chave; quem a define é o Cadastro de Item, spec dona do agregado.

Status é política executável, não rótulo

ItemSupplier.status — os valores, o que cada um libera e o ato que o muda são do Cadastro de Item (RN-ITM-15), e esta página não os repete. O bloqueio do fornecedor inteiro, no eixo Bloqueio desta página, não reescreve a relação: vale pela leitura, junto com o status dela. Na Oracle, o status da ASL determina se o fornecedor pode ser origem do item e se o pedido pode ser aprovado — Debarred impede a aprovação. É controle, não etiqueta.

O eixo de destino existe, e é a UF

Preço e prazo de um mesmo item e fornecedor variam por destino. A ASL da Oracle já tem esse eixo, e o Nexio também tem: shipToStateCode, dentro da chave do ItemSupplierPrice, ao lado de companyId? — as duas são dimensão de preço sem serem também dimensão de status. Destino muda frete e tributação; comprador muda condição negociada; nenhum dos dois muda quem é o fornecedor homologado. É onde a variação tributária mora no condition record do SAP e no price break do Oracle, e o que aqueles dois levam na chave da relação é a organização compradora — no Nexio, o companyId, que já está no preço. A dimensão é a UF, não o ponto de entrega: o que muda preço é frete e tributação, e dois pontos na mesma cidade não têm preço diferente — chavear pelo ponto faria o catálogo crescer sem teto. A busca usa o deliveryStateCode já congelado na linha, então resolver preço não consulta o cadastro do ponto. Preço por sítio específico é negociação, e mora no ContractItem. Ver o Cadastro de Item.

Governança

Estados e bloqueios

O status atual do módulo (Approved / UnderReview / Suspended / Blocked) mistura quatro coisas distintas. Oracle e Ariba as separam, e a separação resolve problemas reais.

EixoValoresResponde
RelacionamentoProspect | SpendAuthorizedAté onde este fornecedor pode ir
Processo de cadastroDraft | UnderReview | Approved | RejectedOnde está o cadastro. UnderReview é a instância SUPPLIER_REGISTRATION aberta no motor; Approved e Rejected são o efeito dela
VigênciaActive | Inactive + inactiveOnSe o registro está em uso
Bloqueiobloqueado + motivo + blockedBy + blockedOnImpedimento operacional pontual

O que cada estado libera

A tabela cruza dois eixos, não um. Ler só o relacionamento é o que deixava o cadastro Rejected convivendo com Prospect convidável — recusado por sanção numa coluna e convidável na outra.

EstadoConvidar para RFQReceber pedidoQualificar
Prospectpermitidobloqueadopermitido
SpendAuthorizedpermitidopermitidopermitido
SpendAuthorized, documento vencidopermitidoconforme política do tipopermitido
SpendAuthorized, bloqueadoavisobloqueadopermitido
Inactivebloqueadobloqueadobloqueado
Cadastro Draftbloqueadobloqueadobloqueado
Cadastro UnderReviewpermitido, com avisobloqueadopermitido
Cadastro Rejectedbloqueadobloqueadobloqueado
SpendAuthorized, sem qualificação vigente na categoria da linhapermitidobloqueado SUPPLIER_NOT_QUALIFIED_FOR_CATEGORY_CONFLICTpermitido
SpendAuthorized, estabelecimento do documento inativo ou com situação cadastral diferente de Activepermitido, com avisobloqueado SUPPLIER_ESTABLISHMENT_NOT_ACTIVE_CONFLICTconforme RN-FOR-05

Cadastro Rejected só sai de Rejected por novo submit, que reabre a instância SUPPLIER_REGISTRATION e volta o processo a UnderReview. Não há caminho que devolva um recusado ao convite sem passar por análise. E receber pedido não é uma linha desta tabela sozinha: entram ainda o estabelecimento do fornecedor apto e a qualificação vigente que cubra a categoria de cada linha do documento (RN-FOR-24). Esta tabela é a regra; quem a aplica é o documento. O código de erro do convite recusado é da spec da Cotação, e o acesso do convidado ao portal — inclusive o do fornecedor bloqueado, que o convite aceita com aviso — é do Portal do Fornecedor.

Pedidos em aberto sobrevivem ao bloqueio e à inativação — bloquear o recebimento de um pedido legítimo já colocado transforma uma decisão de cadastro num problema operacional. E Status + inactiveOn existem em cada nível — fornecedor, estabelecimento, endereço, contato — no padrão consistente da Oracle. Não é um status global.

Qualidade de dados

Antiduplicidade

O Nexio tem uma vantagem estrutural sobre os produtos globais: o CNPJ tem dígito verificador e formato fixo. Isso resolve, de graça, o caso difícil que a Oracle ataca normalizando o taxpayer ID para caracteres alfanuméricos.

#RegraAção
1CNPJ normalizado — 14 caracteres, caixa alta, sem máscara — índice único por tenant onde não nulo (Company, MEI)bloqueia
2CPF normalizado — índice único por tenant onde não nulo (Individual, RuralProducer)bloqueia
3taxIdCountry + foreignTaxId normalizados — índice único por tenant onde não nulos (Foreign)bloqueia
4Raiz do CNPJ já existente na base, inclusive em rascunho ou pendentebloqueia — oferece adicionar o estabelecimento ao fornecedor existente (nome exposto só a usuário interno)
5Similaridade de razão social e nome fantasia (trigram) + domínio de e-mail coincidentealerta com candidatos
6Conta bancária ou chave PIX idêntica entre fornecedores distintosalerta de segurança — é sinal de fraude, não só de duplicidade
7Re-execução na aprovação do cadastroalerta ao aprovador

Verifique também contra rascunhos e cadastros pendentes

É o achado mais subestimado da documentação da Oracle: a checagem considera fornecedores existentes e também solicitações de registro pendentes de aprovação ou salvas para completar depois. Sem isso, dois cadastros do mesmo CNPJ passam juntos pela fila.

Aplique em todos os caminhos de entrada

Tela, importação e API. A Oracle é explícita nisso, e é exatamente onde a maioria das implementações vaza — a validação existe na tela e não existe no POST.

Não revele a colisão ao fornecedor

Vale para toda mensagem que chegue ao fornecedor — e valerá para o autocadastro, quando ele existir: a mensagem não nomeia qual fornecedor colidiu. A Oracle expõe o nome do fornecedor existente apenas a usuários internos. É controle de vazamento de informação, e é fácil de esquecer.

Diferencial

Desempenho do fornecedor

O Nexio tem um ativo que Ariba e Coupa não têm de graça: ele faz o recebimento. OTIF, atraso médio e divergência de quantidade são deriváveis do próprio banco, sem integração e sem pedir nada ao usuário.

MétricaCálculoGranularidade
Pontualidade (OTIF)Recebimentos dentro da janela de tolerância de data, sobre o totalfornecedor · fornecedor × item
Atraso médioMédia de dias entre data prometida e data efetiva, considerando só os atrasadosfornecedor
Divergência de quantidadeRecebimentos fora da tolerância, sobre o totalfornecedor × item
Aderência de preçoDivergência entre preço do pedido e preço da notafornecedor × item
Tempo de resposta a RFQDa data do convite à data da propostafornecedor

Métricas gravadas como agregados versionados em janela móvel, não recalculadas na leitura. E formulário de avaliação de fornecedor fica fora: a adesão é baixíssima e o dado calculado é melhor e gratuito.

Rastreabilidade

Regras de negócio

RN-FOR-01

CNPJ é texto de 14 caracteres, validado por regex e DV

^[A-Z0-9]{12}[0-9]{2}$ mais módulo 11 com valor do caractere igual a ASCII − 48. Gravado sem máscara e em caixa alta; a entrada normaliza minúsculas. Aceitar os dois formatos, numérico e alfanumérico — a Receita continua emitindo CNPJs só numéricos, então "CNPJ novo" não implica "tem letra".

RN-FOR-02

Todo fornecedor tem exatamente um estabelecimento principal

Criado junto com o fornecedor, para todo entityType — é no estabelecimento que vivem a IE por UF (produtor rural tem IE), o endereço fiscal, paymentTerms / currency / defaultIncoterm, receiptTolerance e o padrão de pedido por isPrimary. Para Company e MEI, o principal é a matriz — pelo identificador matriz/filial da Receita, nunca pela ordem do CNPJ — quando ela existe na base. Para Individual e Foreign, o principal é o estabelecimento único criado com o cadastro — sem cnpj, sem establishmentType e sem situação cadastral; a identidade fica na raiz. RuralProducer tem um estabelecimento por propriedade, todos sem CNPJ, cada um identificado pela IE (UF + número) e, havendo, pelo CAEPF; o principal é marcado por isPrimary, e a identidade continua sendo o CPF da raiz. A alternativa "estabelecimento só para quem tem CNPJ" não serve: deixaria produtor rural sem IE e estrangeiro sem moeda e incoterm.

RN-FOR-03

Tipo de pessoa governa a obrigatoriedade

Campo obrigatório para um tipo e inaplicável a outro responde 400 SUPPLIER_FIELD_NOT_APPLICABLE nomeando campo e tipo. Estrangeiro não tem CNPJ, IE, IM, CNAE nem regime tributário brasileiro. A identidade segue o tipo — cnpj no estabelecimento para Company e MEI, cpf na raiz para Individual e RuralProducer, taxIdCountry + foreignTaxId na raiz para Foreign —, cada uma com o seu índice único parcial por tenant, que depende do banco e é verificado na aplicação.

RN-FOR-04

Prospect cota, homologado transaciona

Prospect pode ser convidado a RFQ e qualificado; pedido responde 409 SUPPLIER_NOT_SPEND_AUTHORIZED_CONFLICT. A promoção acontece por homologação aprovada (instância SUPPLIER terminada em Approved) — e por mais nada. Vitória em cotação não promove: ela abre uma qualificação para as categorias do que foi cotado, que percorre o mesmo caminho de todas as outras. Promover por vitória tornaria o convite a uma RFQ o atalho mais barato para contornar a homologação — sem instância, sem motivo codificado, sem certidão e sem varredura de sanção. E promover não basta: quem paga a conta do gasto é a RN-FOR-24.

RN-FOR-05

Situação cadastral diferente de Ativa impede homologar

Suspensa, inapta, baixada ou nula bloqueiam a aprovação da homologação e são reavaliadas na revalidação periódica. Estabelecimento que fica inapto depois de homologado gera alerta e não bloqueia pedido em aberto; pedido novo para esse estabelecimento para de passar (RN-FOR-24). Quem não tem CNPJ não tem situação cadastral, e esta regra não se aplica — a diligência de pessoa física e de estrangeiro é a dos documentos do tipo.

RN-FOR-06

Status de documento é sempre derivado da data

Nunca gravado à mão. A janela de "a vencer" é configurável por tipo. O status da homologação não influencia o vencimento do documento — a relação é só nessa direção.

RN-FOR-07

A política de documento vencido é por tipo e graduada

Warn | RequireJustification | BlockNewOrder. Nenhuma política bloqueia recebimento de pedido já colocado. Como a justificativa de RequireJustification é exigida e registrada no pedido — uso de motivo, flag para o motor, código de erro — é definido pela spec do Pedido.

RN-FOR-08

Requisitos de documento são configuráveis por categoria e faixa de risco

Não existe lista fixa. O motor resolve: dado o fornecedor, suas categorias homologadas e a faixa de risco, quais tipos são exigidos, quais opcionais e quais dispensados.

RN-FOR-09

Homologação é escopada por categoria e a requalificação preserva o escopo

Homologação sem escopo é recusada. Requalificação herda categorias e faixa de risco da anterior.

RN-FOR-10

Sanção pública gera alerta, nunca bloqueio automático

Sanção encontrada abre um SupplierComplianceAlert, que só fecha com decisão registrada (RN-FOR-37). O tenant pode elevar um tipo de sanção a bloqueante por configuração, mas não é o default.

RN-FOR-11

Verificação é append-only

Cada consulta grava fonte, data, resultado e evidência. Nunca sobrescreve a anterior — a série histórica é o que torna a decisão auditável.

RN-FOR-12

Dado bancário nunca é alterado por update

Toda mudança em campo protegido é uma BankAccountChangeProposal: nasce em Draft e, submetida, abre uma instância do motor no processo BANK_ACCOUNT_CHANGE (BankAccount, NoticeContact) ou vai à confirmação por segunda pessoa (ChainContact, RN-FOR-34) — ver RN-FOR-35. O registro vivo permanece intacto até a proposta ser aplicada; "aprovador distinto do solicitante" é a RN-AP-08 do motor, não uma checagem deste módulo. Vale para tela, API e importação. O conjunto de campos protegidos tem núcleo que configuração não reduz (RN-FOR-28), e a única entrada de conta sem instância do motor é a carga inicial de implantação (RN-FOR-31).

RN-FOR-13

Titular diferente do fornecedor é recusado; só Foreign segue com flag

A comparação segue o tipo de pessoa. Company compara pela raiz do CNPJ, que é o que permite a filial receber na conta da matriz. MEI compara o documento inteiro e aceita tanto o CNPJ quanto o CPF do titular, que é o ownerCpf gravado na raiz — a conta de MEI é conta de pessoa física no mundo real, e tratá-la como divergência produziria recusa em cem por cento dos MEIs. Individual e RuralProducer comparam o CPF da raiz. Nesses quatro tipos, titular diferente é recusado: holderTaxId que não confere — ou documento devolvido pela resolução da chave PIX no DICT que não confere — responde 422 BANK_HOLDER_MISMATCH_UNPROCESSABLE no :submit da proposta, e a proposta não abre; na carga inicial, a linha é recusada pela mesma regra (RN-FOR-31). Só Foreign, que não tem documento brasileiro a comparar, segue com veredito de nome — holderName contra legalName, em forma normalizada, gravado com fonte e data —: nome que não confere não recusa, grava a flag "titular ≠ fornecedor", que aciona o passo complementar da controladoria semeado no Fluxo, e o comprovante de titularidade continua obrigatório (RN-FOR-35). Não existe exceção fora destas regras. Pagamento a terceiro — cessão de crédito, factoring, FIDC — não entra pela conta do cadastro: é v2 ou tratado no ERP (Fora de escopo). Por quê: pagar a quem não é o fornecedor é o desvio que o controle existe para impedir; o documento do titular brasileiro é verificável, e o que é verificável se recusa em vez de se aprovar com justificativa. Falso positivo crônico continua sendo o modo de morte de um controle — por isso a filial recebe na conta da matriz e o MEI, na conta do empresário.

RN-FOR-14

Chave PIX aleatória exige resolução de titularidade

Sem verificação bem-sucedida no DICT, a chave fica em estado não verificado e não é oferecida como destino de pagamento.

RN-FOR-15

CNPJ é único por tenant, verificado contra pendentes

A checagem cobre ativos, rascunhos e cadastros pendentes de aprovação, em todos os caminhos de entrada. Vale igual para a raiz do CNPJ (RN-FOR-33).

RN-FOR-16

Fornecedor não é excluído

Havendo RFQ, pedido, recebimento ou nota, apenas inativação. O DELETE existe só para cadastro em rascunho nunca submetido.

RN-FOR-17

Bloqueio exige motivo e registra autor

motivo, blockedBy e blockedOn são obrigatórios. Desbloqueio idem. Sem isso, ninguém sabe por que aquele fornecedor está parado há seis meses.

RN-FOR-18

Categoria declarada não autoriza compra

Serve a convite de RFQ e busca. A autorização vem da consulta às qualificações vigentes (RN-FOR-24); ItemSupplier.status é trava adicional por item, quando a relação existe — nunca o gate, porque item sem ItemSupplier não teria gate nenhum.

RN-FOR-19

Concorrência otimista em todo update

expectedVersion obrigatório no corpo do PUT, checado antes de tocar o agregado.

RN-FOR-20

Auditoria com diff de campos e log de acesso a dado pessoal

IAuditableEntity, categoria Supplier. Além do diff, registrar quem visualizou CPF de quem, e quando — exigência prática da LGPD.

RN-FOR-21

O canal do aviso é campo protegido, como o destino do dinheiro

E-mail e telefone de contato com papel Finance só mudam por proposta, pela mesma entidade e pela mesma instância BANK_ACCOUNT_CHANGE, com changeKind = NoticeContact. Tentativa por PUT, por tela ou por importação responde 409 SUPPLIER_CONTACT_PROTECTED_FIELD_CONFLICT; criar contato Finance é a mesma mudança, salvo o contato livre do cadastro ainda não aprovado e o primeiro contato do aviso, que a RN-FOR-34 trata. O resolvedor Previous lê o contato vigente antes da alteração proposta — e, enquanto houver alteração de contato aplicada com usableFrom no futuro, o valor anterior a ela (RN-FOR-34). O aviso sai só por e-mail; o telefone do contato é origem possível do callback (RN-FOR-29), não um segundo canal de aviso. Não havendo contato Finance com e-mail, a cadeia cai para as três posições de reserva da RN-FOR-34 — o contato PortalAdmin, o contato Commercial designado e o contato designado do estabelecimento principal —, nesta ordem, e para nenhum outro contato nem para o e-mail de SupplierAddress; se nenhum e-mail fora do tenant existir, a proposta não abre (422 BANK_CHANGE_NO_EXTERNAL_NOTICE_CHANNEL_UNPROCESSABLE). O administrador do tenant recebe cópia e nunca substitui o fornecedor como destinatário: aviso que não sai da empresa não avisa ninguém. Por quê: sem esta regra o ataque cabe numa sessão — reescrever os contatos, abrir a proposta bancária, receber o próprio aviso.

RN-FOR-22

Conta aprovada só é destino de pagamento a partir de usableFrom

O contrato de desfecho grava usableFrom = decidedAt + bankChangeGraceHours ao aplicar a proposta. Conta com usableFrom no futuro não entra no pacote enviado ao ERP — a seleção do destino de pagamento filtra por usableFrom <= agora e contestedAt nulo; pedir conta em carência responde 409 BANK_ACCOUNT_NOT_USABLE_YET_CONFLICT, e conta contestada, 409 BANK_ACCOUNT_CONTESTED_CONFLICT. A data não anda para trás, não é editável por PUT e não tem rota de antecipação: uma carência que se pode encurtar sob pressão é a carência que não existe justamente no dia em que ela importa. A conta anterior continua vigente e pagável durante a janela.

RN-FOR-23

Entre o aviso e a primeira decisão há janela mínima

A proposta grava noticeSentAt quando o provedor de e-mail aceita o aviso. Nenhuma tarefa da instância é ativada antes de noticeSentAt + minNoticeHours (configuração do tenant, mínimo 12 h, padrão 24): o Fornecedor entrega esse instante ao motor no gancho genérico activationNotBefore, e decidir tarefa ainda não ativada é recusado pelo motor. E-mail devolvido não inicia a janela: a devolução grava noticeBouncedAt (e emailBouncedAt no contato) e o aviso segue para o próximo e-mail da cadeia da RN-FOR-21. Enquanto nenhum passo ativou, o Fornecedor adia activationNotBefore para o novo envio + minNoticeHours pela rota interna POST /approvals/{id}/activation-window do Fluxo (RN-AP-63), que só anda para frente. Sem próximo e-mail, o Fornecedor cancela a instância (POST /approvals/{id}/cancel), a proposta vai a Cancelled e o alerta vai a quem tem approve:supplier-banks. Para o canal morto não virar tranca, a proposta NoticeContact que corrige um e-mail devolvido abre mesmo sem e-mail entregável, com previousNoticeUndeliverable = true: exige callback Confirmed para telefone confiável ou, sem nenhum telefone confiável depois da consulta nova ao provedor, segue a troca de canal sem telefone da RN-FOR-34 — noTrustedPhone, pedido assinado anexado, com o rastro gravado pelo desfecho (RN-FOR-40), e 7 dias de carência —; nos dois casos aciona o complementar da controladoria. Como a devolução pode chegar com as tarefas já ativas, o contrato de desfecho reconfere na decisão que concluiria a instância: sem envio não devolvido há pelo menos minNoticeHours, devolve Refused(BANK_CHANGE_NOTICE_NOT_DELIVERED_CONFLICT) — a decisão não é gravada e a tarefa continua ativa. O aviso existe para dar ao fornecedor legítimo a chance de dizer "não fui eu" antes da troca; disparado e aprovado no mesmo minuto, ele só documenta a fraude. A guarda de ativação vive no motor; a de entrega, no desfecho do Fornecedor.

RN-FOR-24

Gasto é autorizado por qualificação vigente na categoria, não por estado

Emitir pedido exige, cumulativamente: relacionamento SpendAuthorized, processo de cadastro Approved, fornecedor não bloqueado, estabelecimento do fornecedor apto e uma SupplierQualification vigente cujo escopo cubra a categoria de cada linha. A cobertura casa por prefixo de path do nó — qualificado em /SERVICOS/ cobre /SERVICOS/LIMPEZA/, e nunca o contrário. "Vigente" é validTo nulo ou futuro na data de submissão do documento. Linha fora do escopo responde 409 SUPPLIER_NOT_QUALIFIED_FOR_CATEGORY_CONFLICT, nomeando o fornecedor e o nó pedido. Estabelecimento apto é o estabelecimento do fornecedor escolhido no documento — o principal, quando nenhum é escolhido — com vigência Active e, quando tem CNPJ, registrationStatus = Active na última verificação registrada, desde que feita há no máximo 45 dias; Suspended, Unfit, ClosedDown, Null, verificação mais velha que isso ou nenhuma verificação respondem 409 SUPPLIER_ESTABLISHMENT_NOT_ACTIVE_CONFLICT, nomeando o estabelecimento e a situação. A matriz ativa não empresta aptidão à filial baixada, nem o contrário. Pedido já emitido não é afetado — a mudança de situação gera alerta (RN-FOR-05). Quando a última qualificação vence, o relacionamento não é rebaixado — estado não é o gate: o fornecedor segue SpendAuthorized, segue convidável e qualificável, pedidos em aberto seguem vivos, e apenas pedido novo deixa de passar. O aviso é antecipado, a 30, 15 e 5 dias de validTo, e repetido na expiração. Sem isso, aprovar a Beta em limpeza a autorizaria a vender ácido sulfúrico.

RN-FOR-25

Documento de escopo de estabelecimento declara qual estabelecimento

SupplierDocument.supplierEstablishmentId é obrigatório quando scope = Establishment e proibido quando scope = Supplier — descumprir responde 400 SUPPLIER_DOCUMENT_ESTABLISHMENT_REQUIRED. Seis dos treze tipos-semente são por estabelecimento; sem a coluna, três alvarás de três filiais são três linhas indistinguíveis e o pacote exigido não sabe dizer que falta o da Bahia. O requisito é resolvido por estabelecimento ativo, e a promessa "filial baixada com a matriz ativa" passa a valer também para a documentação: estabelecimento inativo sai do pacote.

RN-FOR-26

Certidão sem fonte automatizada é entrada manual com vigência, e o aviso vem antes

CND/CPEN federal, CRF do FGTS e CNDT não têm consulta automatizada na v1 — as fontes existem, o acesso programático não. Elas são SupplierDocument com número, órgão, emissão e vencimento digitados ou lidos do PDF enviado, e o status continua derivado da data (RN-FOR-06). O aviso dispara antes do vencimento — 30, 15 e 5 dias —, nunca só depois: certidão avisada no dia seguinte ao vencimento é pedido travado sem aviso prévio. A consulta automática entra na v2, pelo mesmo gancho de provedor plugável da consulta ao CNPJ: o provedor devolve número, emissão, vencimento e comprovante, e grava SupplierVerification e SupplierDocument como a entrada manual grava. Até lá, a página diz que não existe, em vez de prometer varredura que ninguém escreveu. Sanções (CEIS, CNEP) seguem automáticas desde a v1, e o bloqueio por certidão vencida segue a política do tipo (RN-FOR-07).

RN-FOR-27

O bloco bancário segue o tipo de pessoa

accountKind = Domestic exige ISPB, agência e conta e aceita chave PIX; International exige IBAN ou conta mais código de compensação local, SWIFT/BIC e país, e aceita banco intermediário. Foreign aceita os dois blocos — há fornecedor estrangeiro com conta no Brasil. Company, MEI, Individual e RuralProducer aceitam apenas Domestic na v1. Campo do bloco errado responde 400 SUPPLIER_FIELD_NOT_APPLICABLE, nomeando campo e bloco. Por quê: o produto sustenta Foreign com moeda, incoterm e um módulo de câmbio inteiro — havia onde comprar e não havia onde pagar.

RN-FOR-28

O núcleo bancário não é configurável

São do núcleo protegido todos os campos de SupplierBankAccount que dizem para onde o dinheiro vai — accountKind, ispb/compeCode, branchNumber/branchCheckDigit/accountNumber/accountCheckDigit, accountType, pixKeyType/pixKey, iban, swiftBic, bankCountryCode, bankName, routingCodeType, intermediaryBankSwiftBic/intermediaryBankName, holderName/holderTaxId — e o e-mail e o telefone de todo contato com papel Finance. Ficam fora só os campos gerados (validFrom/validTo, holderVerification, usableFrom, contestedAt). O núcleo muda só por proposta, em tela, API e importação; a importação aceita Propose ou Reject para campo protegido, e não existe terceiro valor. O tenant pode acrescentar campos protegidos fora do núcleo, na configuração protectedSupplierFields; a lista nunca retira campo do núcleo. Mudar essa lista é ato de controle: grava o registro do ato na mesma transação, com autor, antes e depois; publica supplier-protected-fields.changed depois do commit; e avisa obrigatoriamente todos os que têm approve:supplier-banks. Por quê: controle que um administrador desliga sozinho, sem ninguém saber, é preferência, não controle.

RN-FOR-29

Callback de saída para telefone confiável; sem telefone confiável, controladoria e prova documental

O callback é ligação de saída, feita pelo comprador para um telefone confiável do fornecedor, falando com a pessoa responsável por ele. Telefone confiável é, e só é: AgedContactPhone — phone ou mobile de contato ativo com papel Finance ou numa posição da cadeia de reserva do aviso (PortalAdmin, Commercial designado, contato designado do estabelecimento principal — RN-FOR-34), com pelo menos 30 dias até a submissão da proposta, contados do mais tarde entre a gravação do número (phoneRecordedAt, mobileRecordedAt) e a entrada do contato em Finance ou na cadeia (noticeChainSince), reativação inclusa; ou RegistryLookup — telefone devolvido pela consulta mais recente ao CNPJ feita pelo provedor, gravada em SupplierVerification com fonte e data, que, quando uma consulta anterior do mesmo CNPJ devolveu outro telefone ou nenhum, só vale 30 dias depois da primeira consulta que o devolveu. Contato fora dessas posições não é fonte — Technical, Quality, Tax e o Commercial não designado —, qualquer que seja a idade do número: são gravados pelo PUT livre de contatos, sem segunda pessoa, e um número plantado ali hoje valeria como callback daqui a 30 dias; pela mesma razão, o número que um desses contatos já tinha só começa a contar quando ele entra em Finance ou na cadeia. Verificação manual de CNPJ nunca é fonte de telefone, e quem é proponente de proposta do fornecedor em Draft ou Open não registra verificação manual dele (409 SUPPLIER_VERIFICATION_BY_PROPONENT_CONFLICT). Pessoas ligadas ao número: quem o gravou (phoneRecordedByUserId e equivalentes); quando o número entrou por alteração de contato (phoneChangeProposalId e equivalentes), quem propôs, quem confirmou (confirmedByUserId), quem registrou o callback e quem decidiu na instância daquela proposta; quando entrou pela carga inicial, quem enviou e quem confirmou o lote — o contato da carga guarda em phoneChangeProposalId e equivalentes a proposta origin = InitialLoad da linha (RN-FOR-31); e as mesmas pessoas da proposta que pôs o contato em Finance ou na cadeia (noticeChainProposalId). A comparação é por usuário e por CPF verificado (RN-FOR-36). Número fora das duas fontes não é telefone confiável, e número ligado ao proponente não serve à proposta dele: registrar callback para qualquer dos dois responde 422 BANK_CHANGE_CALLBACK_PHONE_NOT_TRUSTED_UNPROCESSABLE. Separação: quem registra tem approve:supplier-banks, não é o proponente e não é pessoa ligada ao número usado (409 BANK_CHANGE_APPROVER_IS_REQUESTER_CONFLICT). O registro — POST /suppliers/{id}/change-proposals/{pid}:record-callback, só em proposta Open, de qualquer changeKind — grava número, origem, o contato ou a verificação de onde o número saiu (callbackSourceId), quem ligou, quando, com quem falou, resultado e callbackDataHash, uma vez só (409 BANK_CHANGE_CALLBACK_ALREADY_RECORDED_CONFLICT); tentativa sem atendimento vai à trilha como supplier-bank-change-proposal.callback-attempted. Na decisão que concluiria a instância — ou, em ChainContact, na confirmação (RN-FOR-34) — o Fornecedor exige callbackResult = Confirmed com callbackDataHash igual ao dataHash da proposta; faltando, o contrato de desfecho devolve Refused(BANK_CHANGE_CALLBACK_REQUIRED_CONFLICT) — a decisão não é gravada e a tarefa continua ativa — e a confirmação responde 409 com o mesmo código. Denied contesta a proposta (RN-FOR-30). Nunca se conclui "sem telefone" sem perguntar: na submissão, sem AgedContactPhone elegível e não ligado ao proponente, o Fornecedor faz uma consulta nova ao provedor pelo CNPJ do estabelecimento principal e a grava; provedor indisponível recusa a submissão (503 BANK_CHANGE_REGISTRY_LOOKUP_UNAVAILABLE), e fornecedor sem CNPJ (Individual, RuralProducer, Foreign) não tem consulta a fazer. Número descartado só por estar ligado ao proponente nunca vale como falta de telefone: se, depois da consulta, os únicos telefones que seriam confiáveis estão ligados a ele, a submissão — de conta ou de canal — é recusada com 409 BANK_CHANGE_APPROVER_IS_REQUESTER_CONFLICT, nada é gravado e noTrustedPhone não nasce; a troca recomeça por proposta de pessoa não ligada ao número. Só sem nenhum telefone confiável, ligado ou não, o sistema grava noTrustedPhone = true, que o motor recebe como flag e que aciona o passo complementar da controladoria semeado no Fluxo; aí o callback não é exigido e a prova documental toma o lugar dele: na proposta BankAccount, a titularidade (RN-FOR-35), que é obrigatória de qualquer jeito; na proposta de canal — NoticeContact ou ChainContact —, que não tem conta a comprovar, o pedido de troca assinado pelo fornecedor anexado, com o rastro gravado pelo desfecho e sem conferência do documento (RN-FOR-40), e a carência de 7 dias da RN-FOR-34. A flag é calculada, nunca declarada por quem propõe. Consentimento do contato não é condição: a base é prevenção a fraude.

RN-FOR-30

O fornecedor legítimo tem por onde dizer "não fui eu"

Toda proposta Standard, de qualquer changeKind, emite um token de contestação — aleatório, com pelo menos 128 bits, guardado só como hash — em cada e-mail ao canal anterior: o aviso da proposta e o aviso de aplicação. Cada emissão invalida a anterior. O token vale até a proposta ficar Rejected ou Cancelled, ou até 30 dias depois de usableFrom, e é de uso único. O link abre uma página sem login que mostra o nome do comprador, a espécie da mudança e a data da proposta — nunca a conta nem o contato propostos — e um único ato, POST /portal/bank-change-contests, com o token no corpo — o link o leva no fragmento, que não chega a log nenhum —, sem permissão e sem sessão, declarado no Portal do Fornecedor. Token desconhecido, usado ou vencido responde o mesmo 401 BANK_CHANGE_CONTEST_TOKEN_INVALID_UNAUTHORIZED, sem dizer qual dos três. A contestação também entra por dentro, e aí é ato de controle com segunda pessoa: quem tem read:supplier-banks registra, com nota, a ligação ou a mensagem recebida por canal independente (POST /suppliers/{id}/change-proposals/{pid}:contest), e a contestação só produz efeito quando outra pessoa — outro usuário e outra chave de pessoa, também com read:supplier-banks — confirma pela mesma rota; até lá fica registrada e sem efeito, e a mesma pessoa confirmando responde 409 SUPPLIER_CONTACT_CONTEST_SECOND_PERSON_REQUIRED_CONFLICT. As duas pontas são de controle: quem registra e quem confirma precisam de identidade verificada com CPF único por tenant (RN-FOR-36) — sem ela, 409 SUPPLIER_CONTACT_CONTEST_IDENTITY_NOT_VERIFIED_CONFLICT, e nada é gravado —, e conceder read:supplier-banks é ato de controle, com registro e aviso (RN-FOR-36). Por quê: exigida só a permissão de leitura, dois usuários criados na hora revertiam qualquer troca legítima de canal e travavam todas as propostas do fornecedor — negação de serviço com duas contas. A contestação pelo link não precisa de segunda pessoa — quem a faz é o fornecedor — e o callback com Denied contesta sozinho. Efeito, na mesma transação: proposta Open vai a Contested e a instância, quando há, é cancelada (POST /approvals/{id}/cancel, como a definição do BANK_ACCOUNT_CHANGE no Fluxo prevê); proposta de contato Applied segue a RN-FOR-38; proposta de conta Applied vai a Contested, a conta criada por ela ganha contestedAt e deixa de ser destino de pagamento, e a versão anterior não é reaberta — é esta a suspensão da proposta aplicada que o Fluxo deixa ao Fornecedor, e não existe outra. Pela rota interna, contestar proposta em estado final responde 409 BANK_CHANGE_PROPOSAL_NOT_CONTESTABLE_CONFLICT. Contested é final: troca legítima contestada por engano recomeça por proposta nova, com aviso, janela e callback. Depois do commit sai supplier-bank-change-proposal.contested, com aviso obrigatório a quem tem approve:supplier-banks e ao administrador do tenant. Por quê: janela sem porta de saída é espera, não controle.

RN-FOR-31

Carga inicial de implantação é exceção declarada, com janela única e dupla custódia

É a única entrada de conta sem instância do motor. Janela: aberta desde a criação do tenant e fechada, sem reabertura, no primeiro destes três: a confirmação de um lote, o fechamento explícito por quem tem approve:supplier-banks (POST /suppliers/bank-accounts:close-initial-load), ou 60 dias corridos da criação do tenant; o fechamento grava bankInitialLoadClosedAt na configuração do tenant, ao lado de bankChangeGraceHours. Fora da janela, 409 BANK_INITIAL_LOAD_WINDOW_CLOSED_CONFLICT. Alcance: só fornecedor sem nenhuma SupplierBankAccount e sem proposta Open — a carga nunca substitui conta existente; linha fora disso responde 409 BANK_INITIAL_LOAD_SUPPLIER_HAS_ACCOUNT_CONFLICT, e o lote inteiro não grava. Linha cujo titular não confere com o fornecedor responde 422 BANK_HOLDER_MISMATCH_UNPROCESSABLE (RN-FOR-13), com a mesma consequência. A linha pode trazer os contatos Finance do fornecedor, que entram sob a mesma dupla custódia, sem virar proposta, com phoneSource = InitialLoad, a proposta da linha em phoneChangeProposalId e equivalentes, e o relógio de confiança começando na confirmação; quem enviou e quem confirmou o lote são pessoas ligadas a esses números (RN-FOR-29). Cada conta carregada precisa de evidência antes da confirmação: comprovante de titularidade (tipo de anexo BANK_OWNERSHIP_PROOF) anexado à proposta que a linha criou — a BankAccountChangeProposal com origin = InitialLoad é a dona do anexo, e é a única proposta fora de Draft que aceita anexo, só até a confirmação do lote —, ou callback Confirmed para telefone devolvido pela consulta ao CNPJ feita pelo provedor; a confirmação pergunta ao Anexo pelo veredito de cada comprovante, como a submissão pergunta: a lista dos estados é contrato desta página, completa e final, e o Anexo a copia literalmente. Conta como falta de evidência — 409 BANK_INITIAL_LOAD_EVIDENCE_MISSING_CONFLICT, listando as linhas e o estado de cada uma, e nada é gravado: linha sem comprovante e sem callback Confirmed; comprovante revogado; arquivo eliminado; veredito Infected; anexo em estado reprovado pelo contrato do dono; veredito Failed; e reserva de envio Reserved ainda confirmável, que é anexo sem arquivo e pode expirar sem nunca virar um. Conta como espera, e só quando não há nenhuma falta desta lista: Pending e Scanning, as duas fases da varredura, que recusam a confirmação com o 409 do Anexo, ATTACHMENT_SCAN_PENDING_CONFLICT, que esta página cita e não redefine. Failed é falta, não espera: o veredito diz que a varredura não concluiu, sair dele depende de um ato de alguém (:rescan, do Anexo) que ninguém é obrigado a fazer, e confirmar lote à espera desse ato deixaria a janela de 60 dias correr contra o controle; o caminho é varredura nova liberada, ou comprovante novo, e a confirmação repetida. Ao Anexo, o descritor responde pela proposta InitialLoad StateOf = InProgress — ela nasce Open, nunca Draft — e aceita escrita de anexo até a confirmação ou o cancelamento do lote; depois, fecha como toda proposta submetida (RN-FOR-35). Dupla custódia: quem tem propose:supplier-banks e identidade verificada (RN-FOR-36) envia o arquivo por POST /suppliers/bank-accounts:initial-load, com dryRun=true obrigatório antes; sem dryRun, as linhas são gravadas como BankAccountChangeProposal com origin = InitialLoad, status = Open, o mesmo initialLoadBatchId e o hash do arquivo. Outra pessoa, com approve:supplier-banks e identidade verificada (RN-FOR-36), confirma por POST /suppliers/bank-accounts:confirm-initial-load informando lote e hash — o do arquivo somado aos identificadores dos comprovantes anexados, que a tela de confirmação mostra —; pessoa igual — mesmo usuário ou mesmo CPF verificado — responde 409 BANK_CHANGE_APPROVER_IS_REQUESTER_CONFLICT, hash diferente 409 BANK_INITIAL_LOAD_HASH_MISMATCH_CONFLICT. A confirmação grava confirmedByUserId nas propostas do lote e aplica o lote inteiro numa transação — usableFrom = confirmação + bankChangeGraceHours, verificação de titularidade e alertas de padrão como em qualquer conta —, fecha a janela, grava o registro do ato de controle e publica supplier-bank-accounts.initial-loaded depois do commit, com contagem e hash. A primeira conferência com o ERP (RN-FOR-32) roda logo depois. Lote não confirmado quando a janela fecha vai a Cancelled. A primeira carga em produção depende do requisito de identidade verificada da demanda de plataforma (RN-FOR-36).

RN-FOR-32

O Nexio é a fonte da verdade da conta, e confere o ERP todo dia

A conta do fornecedor é gravada, versionada e decidida no Nexio, e é o Nexio que a envia ao ERP; o ERP não é fonte de conta. Uma conferência diária por tenant, em horário configurável, lê do ERP, para cada fornecedor integrado, o destino de pagamento ativo e o compara com a conta utilizável no Nexio (usableFrom <= agora, contestedAt nulo) — ISPB, agência e conta, ou chave PIX, ou IBAN, conforme o bloco. Cada conferência grava uma SupplierVerification com fonte ErpBankAccount e resultado Match | Divergent | Unavailable. Divergent abre alerta de segurança com aviso obrigatório, por InApp e Email, a todos os que têm approve:supplier-banks e ao administrador do tenant; o alerta se repete a cada conferência enquanto a divergência durar, e o próximo pacote ao ERP reenvia a conta do Nexio. O Nexio não adota a conta do ERP: se a troca lá foi legítima, o caminho é proposta aqui. Unavailable — adaptador sem leitura, ERP fora do ar — é gravado como tal, nunca como conferido, e três dias seguidos sem conferência também geram o alerta. A conferência depende de o adaptador de ERP expor a leitura do destino de pagamento: sem ela, a primeira integração de pagamento não vai a produção.

RN-FOR-33

A raiz do CNPJ é única por tenant, e grupo econômico é parentSupplierId

cnpjRoot é único por tenant onde não nulo, verificado contra ativos, rascunhos e pendentes em todos os caminhos de entrada. Criar fornecedor com raiz existente responde 409 SUPPLIER_DUPLICATE_CONFLICT; para usuário interno, a resposta traz o fornecedor existente e a oferta de adicionar o estabelecimento. Todo estabelecimento com CNPJ tem os oito primeiros caracteres iguais a Supplier.cnpjRoot; estabelecimento de outra raiz responde 409 SUPPLIER_ESTABLISHMENT_ROOT_MISMATCH_CONFLICT — pessoa jurídica diferente é fornecedor diferente, ligado, se for o caso, por parentSupplierId. A raiz é imutável; cadastro com raiz errada se corrige inativando o fornecedor e cadastrando outro. parentSupplierId não aponta para fornecedor da mesma raiz nem forma ciclo (400 SUPPLIER_PARENT_INVALID). A comparação de titular pela raiz (RN-FOR-13) e o alerta de conta repetida entre fornecedores leem a raiz, nunca o grupo: conta da controladora não é conta da controlada.

RN-FOR-34

Contato que recebe o aviso ou atende o callback muda por alteração protegida

E-mail, phone e mobile de contato Finance mudam por proposta NoticeContact, na instância BANK_ACCOUNT_CHANGE (RN-FOR-21). A cadeia de reserva do aviso tem três posições, e só elas: o contato com papel PortalAdmin (exatamente um ativo); o contato Commercial designado (noticeChainSlot = DesignatedCommercial, no máximo um ativo, com o papel Commercial); e o contato do estabelecimento principal, que é o contato designado com noticeChainSlot = PrincipalEstablishment — no máximo um ativo, vinculado ao estabelecimento principal pelo supplierEstablishmentId. Os demais contatos Commercial são livres e nunca são fonte de telefone confiável nem canal de aviso; phone e email de SupplierAddress também não. E-mail e telefones dos contatos da cadeia mudam por alteração protegida de contato, changeKind = ChainContact, sem instância do motor salvo nos casos desta regra e da RN-FOR-38. As duas nascem pela mesma rota, POST /suppliers/{id}/contacts/change-proposals, em Draft, e o changeKind é calculado pelos papéis do contato antes e depois da mudança — Finance em qualquer dos lados é NoticeContact, salvo no primeiro contato do aviso —, nunca declarado. Vale para tela, PUT /suppliers/{id}/contacts (409 SUPPLIER_CONTACT_PROTECTED_FIELD_CONFLICT) e importação; criar, inativar, reativar, dar e tirar um desses papéis ou designar e retirar uma posição é a mesma alteração, e a proposta que põe um contato em Finance ou na cadeia leva o e-mail e os telefones dele no dataHash. Sem telefone confiável, a troca de canal vai à instância com pedido assinado: na submissão procura-se AgedContactPhone elegível e não ligado ao proponente e, faltando, faz-se a consulta nova ao provedor (RN-FOR-29); número que só falta por estar ligado ao proponente recusa a submissão, como lá. Não havendo telefone confiável, a proposta — NoticeContact ou ChainContact — grava noTrustedPhone = true e abre a instância BANK_ACCOUNT_CHANGE com o complementar da controladoria semeado no Fluxo; o callback não é exigido e, no lugar dele, a submissão exige anexo à proposta do tipo SIGNED_CONTACT_CHANGE_REQUEST — o pedido de troca do próprio fornecedor, na forma que a norma da empresa exigir, que o sistema exige mas não confere (RN-FOR-40) — com veredito do antivírus Available. Sem ele, 422 SUPPLIER_CONTACT_CHANGE_NO_TRUSTED_PHONE_UNPROCESSABLE, e anexo ainda em varredura segue o 409 do Anexo. O veredito do antivírus não confere a assinatura, e a decisão também não: a troca é aplicada com o anexo exigido e o rastro gravado pelo desfecho — o anexo, quem o anexou e quando, quem decidiu e quando (RN-FOR-40). Aplicada, essa troca tem usableFrom = aplicação + 7 dias, qualquer que seja bankChangeGraceHours. Confirmação do ChainContact: a submissão avisa por e-mail o endereço anterior, com link de contestação (RN-FOR-30); e-mail devolvido grava noticeBouncedAt e o aviso segue ao próximo e-mail da cadeia, como na RN-FOR-23. A proposta só é aplicada quando outra pessoa, com approve:supplier-banks, a confirma por POST /suppliers/{id}/change-proposals/{pid}:confirm (ou recusa por :reject), gravando confirmedByUserId e confirmedAt. A confirmação exige, na hora: envio sem devolução há pelo menos minNoticeHours — antes disso, 409 SUPPLIER_CONTACT_CHANGE_WINDOW_NOT_ELAPSED_CONFLICT; só com envios devolvidos, 409 BANK_CHANGE_NOTICE_NOT_DELIVERED_CONFLICT — e callback Confirmed para telefone confiável com o dataHash da proposta (409 BANK_CHANGE_CALLBACK_REQUIRED_CONFLICT); confirmador igual ao proponente, 409 BANK_CHANGE_APPROVER_IS_REQUESTER_CONFLICT. Sem próximo e-mail na cadeia, a proposta vai a Cancelled, e o canal morto se corrige como na RN-FOR-23, pela instância, com previousNoticeUndeliverable. Aplicada, a alteração de contato — das duas espécies — grava usableFrom = aplicação + bankChangeGraceHours — ou aplicação + 7 dias, com noTrustedPhone — na proposta, e o aviso de aplicação vai ao endereço anterior com novo link de contestação (RN-FOR-38); até usableFrom, o aviso bancário do fornecedor continua indo ao valor anterior. Todo número gravado e toda entrada na cadeia reiniciam o relógio de confiança: o número novo só é telefone confiável 30 dias depois de aplicado, e o contato guarda de qual proposta ele veio (phoneChangeProposalId, mobileChangeProposalId, emailChangeProposalId); o contato que entra em Finance ou numa posição da cadeia — criado, com papel ou posição dada, ou reativado — grava noticeChainSince e noticeChainProposalId, e os números que ele já tinha contam dali. Contato livre só antes da aprovação: enquanto o cadastro está em Draft ou UnderReview, nunca foi Approved e não há proposta do fornecedor fora de Draft, contato Finance ou da cadeia é criado e editado pelo PUT, e o relógio conta da gravação. Depois — fornecedor migrado incluso —, o primeiro contato do aviso (fornecedor sem contato ativo Finance nem em posição da cadeia) é ChainContact, qualquer que seja o papel: sem endereço anterior não há aviso nem janela, e a confirmação por segunda pessoa exige callback Confirmed para o telefone do RegistryLookup da consulta nova; sem telefone ali, segue a instância com pedido assinado desta regra. Por quê: um colega honesto que cadastra o celular que o fraudador mandou por e-mail planta o telefone do callback sem saber; o relógio, a segunda pessoa e a ligação para o número que já se conhecia são o que separa as duas coisas.

RN-FOR-35

A proposta nasce em rascunho, recebe a titularidade e, submetida, não muda mais

As rotas de criação de proposta criam em Draft, editável só pelo proponente (PUT /suppliers/{id}/change-proposals/{pid}) e descartável (DELETE, só em Draft); do rascunho não sai aviso, token nem instância. Submeter (POST /suppliers/{id}/change-proposals/{pid}:submit) exige, na proposta BankAccount que inclui ou substitui conta, comprovante de titularidade anexado à proposta, no tipo de anexo BANK_OWNERSHIP_PROOF — documento do banco que mostra o titular com o documento que a RN-FOR-13 compara (a raiz do CNPJ em Company) — com veredito do antivírus Available; sem ele, 409 BANK_CHANGE_OWNERSHIP_EVIDENCE_REQUIRED_CONFLICT, e anexo ainda em varredura segue o 409 do Anexo. A consulta automática de titularidade é gancho de provedor; o DICT, quando resolve a chave PIX, soma à evidência e não a substitui. Na submissão o Fornecedor, nesta ordem: recusa proponente sem identidade verificada (RN-FOR-36); recusa fornecedor com propostas de conta travadas (RN-FOR-38); compara o titular e recusa o que não confere (RN-FOR-13); procura telefone confiável, com consulta nova ao provedor quando falta, e recusa o que só falta por estar ligado ao proponente (RN-FOR-29); grava submittedAt e dataHash; calcula as flags; emite o aviso; e abre a instância com o proponente e as pessoas ligadas por correção de identidade entre os excluídos (RN-AP-60 do Fluxo; RN-FOR-41) — ou, em ChainContact fora de bloqueio e com telefone confiável, só avisa (RN-FOR-34). Depois de submetida a proposta é imutável: PUT e DELETE respondem 409 BANK_CHANGE_PROPOSAL_IMMUTABLE_CONFLICT; anexo novo e revogação de anexo, que são rotas do Anexo, respondem o código dele, 409 ATTACHMENT_OWNER_NOT_WRITABLE_CONFLICT, porque o descritor da proposta a declara fechada à escrita. A prova precisa continuar de pé na decisão: na decisão que concluiria a instância, o contrato de desfecho pergunta ao Anexo pelo comprovante de titularidade ou pelo pedido assinado que a submissão exigiu; revogado, eliminado ou com veredito que deixou de ser Available — Infected depois de nova varredura —, devolve Refused(BANK_CHANGE_EVIDENCE_NOT_AVAILABLE_CONFLICT): a decisão não é gravada, a tarefa continua ativa e o caminho é rejeitar e abrir proposta nova. O Anexo, por sua vez, recusa eliminar anexo de dono com aprovação em curso. Depois da aplicação, a prova que cai não passa em branco: comprovante de titularidade ou pedido assinado que é revogado, eliminado, reprovado ou vai a Infected depois de a conta ser aplicada — ou depois da confirmação do lote da carga inicial (RN-FOR-31) — abre um SupplierComplianceAlert de kind = BankEvidenceLost com a conta, a proposta e o anexo (RN-FOR-37), e a conta deixa de ser destino de pagamento até a decisão do alerta, como contestedAt a faz (RN-FOR-22); a proposta não é revertida e a conta anterior não é reaberta. Decidido o alerta, ou a conta volta com evidência nova anexada a uma proposta nova, ou é encerrada. Não é botão de negação de serviço: revogar ou eliminar prova de controle já passa pela dupla custódia do Anexo. A prova de ato de controle sem conta também não passa em branco: o pedido assinado SIGNED_CONTACT_CHANGE_REQUEST de troca de canal já aplicada (RN-FOR-40) e o comprovante IDENTITY_CORRECTION_PROOF de correção de identidade já aplicada (RN-FOR-39) que são revogados, eliminados, reprovados ou vão a Infected depois da aplicação abrem um SupplierComplianceAlert de kind = ControlEvidenceLost e source = Attachment, com o fornecedor, a proposta ou a instância, e o anexo (RN-FOR-37). Efeito, na mesma transação: na troca de canal, o valor trocado deixa de ser canal de aviso e fonte de telefone confiável e o fornecedor ganha bankProposalsBlockedAt, como na contestação (RN-FOR-38), até a decisão do alerta; na correção de identidade, a identidade não é desfeita — ela já passou pelas unicidades do cadastro —, e a conta vigente cujo titular só confere com a identidade corrigida, e não conferiria com a anterior pelo regime da RN-FOR-13, deixa de ser destino de pagamento até a decisão. Aviso obrigatório, por InApp e Email, a quem tem approve:supplier-banks, a quem tem verify:suppliers e ao administrador do tenant. Por quê: era justamente o rastro que sustentava o risco aceito de não conferir o documento — anexo que desaparece sem alerta desfaz a mitigação inteira. BANK_ACCOUNT_CHANGE não tem devolução — só aprova ou rejeita (Fluxo, RN-AP-61): corrigir é rejeitar e abrir proposta nova, com aviso, janela, callback e carência novos. Callback e titularidade valem para o dataHash com que foram registrados, e só para ele. A primeira conta do fornecedor segue este mesmo caminho: não existe conta nascida no cadastro, e o SUPPLIER_REGISTRATION não aplica dado bancário. Trocar isDefault ou encerrar conta (deactivate) também é proposta, porque muda o destino do pagamento.

RN-FOR-36

Ver a conta sem máscara é permissão própria, e concedê-la é ato de controle

GET /suppliers/{id}/bank-accounts e GET /suppliers/{id}/change-proposals devolvem agência, conta, chave PIX e IBAN mascarados, salvo para quem tem read-unmasked:supplier-banks; o aprovador com tarefa ativa na instância vê o diff sem máscara daquela proposta, e só dela. Quem lê os anexos da conta e da proposta — o comprovante de titularidade e o pedido assinado — é esta lista, e só ela, que o descritor do Anexo implementa no CanRead e copia literalmente: (1) quem tem read-unmasked:supplier-banks, sempre; (2) em proposta origin = Standard, o proponente, com a proposta em Draft ou Open, e quem tem tarefa ativa ou já decidida na instância daquela proposta; (3) em proposta origin = InitialLoad, antes da confirmação do lote, o remetente e quem tem approve:supplier-banks com identidade verificada e não é o remetente — nem pelo usuário, nem pelo CPF —; depois da confirmação, só o confirmador. Ninguém mais. Conceder a papel ou a usuário approve:supplier-banks, propose:supplier-banks, read-unmasked:supplier-banks ou read:supplier-banks — esta última porque é ela que registra e confirma a contestação por dentro (RN-FOR-30) — é ato de controle: registro do ato e aviso obrigatório a todos os que já têm approve:supplier-banks, ao administrador do tenant e ao contato contratual do tenant — quem assinou o contrato com a R&G —, que está fora do alcance de quem administra o tenant. Quem recebe approve:supplier-banks ou propose:supplier-banks precisa de identidade verificada, com CPF único por tenant: dois usuários com o mesmo CPF são uma pessoa, e não somam as duas de um quórum nem fazem as duas pontas de uma separação. Do lado de quem propõe, o :submit de proposta — de conta ou de contato — e o envio da carga inicial (:initial-load sem dryRun) respondem 409 BANK_PROPOSER_IDENTITY_NOT_VERIFIED_CONFLICT para usuário sem identidade verificada, e nada é gravado. Do lado de quem aprova, as ações dessa permissão no Fornecedor — registrar callback, confirmar alteração de contato, confirmar ou fechar a carga inicial — respondem 409 BANK_APPROVER_IDENTITY_NOT_VERIFIED_CONFLICT para usuário sem identidade verificada; e todo decisor de instância BANK_ACCOUNT_CHANGE — do quórum e do complementar da controladoria, qualquer que seja a permissão que o pôs no passo — precisa de identidade verificada e é comparado por CPF com o proponente e com as pessoas ligadas ao número usado no callback: na decisão que concluiria a instância, o contrato de desfecho devolve Refused com o mesmo código quando alguma decisão não vem de CPF verificado ou os CPFs não são distintos entre si e do proponente, e Refused(BANK_CHANGE_APPROVER_IS_REQUESTER_CONFLICT) quando alguma decisão vem do CPF de pessoa ligada ao número do callback (RN-FOR-29). A separação entre pessoas é por CPF nas duas pontas: aprovador, confirmador ou autor do callback que tem o CPF do proponente, do remetente da carga ou de pessoa ligada ao número (RN-FOR-29) é a mesma pessoa, com outro usuário, e a ação responde 409 BANK_CHANGE_APPROVER_IS_REQUESTER_CONFLICT. A concessão acontece no GrydAuth, e os dois mecanismos são requisitos da demanda de plataforma: a publicação da mudança de papel e de permissão bloqueia a primeira proposta bancária em produção; a identidade verificada com CPF único bloqueia a primeira carga e a primeira proposta bancária em produção (RN-FOR-31, RN-FOR-35).

RN-FOR-37

Achado de conformidade é um alerta com dono, estado e decisão

Toda varredura que encontra algo novo abre um SupplierComplianceAlert — supplierId, supplierEstablishmentId?, kind = Sanction | RegistrationStatusChanged | ErpBankDivergence | VerificationStale | BankEvidenceLost | ControlEvidenceLost, source (CEIS | CNEP | CEPIM | Leniency | TcuIneligible | Cnia | SlaveLabor | OfacSdn | Receita | ErpBankAccount | Attachment), a SupplierVerification que o originou, status = Open | Decided | Resolved, decision = KeepWithJustification | FalsePositive | Blocked, decisionNote, decidedByUserId, decidedAt. Existe um alerta aberto por fornecedor, tipo, fonte e registro de origem: a varredura seguinte que acha o mesmo registro não duplica, e a que não o acha mais o leva a Resolved por sistema. Os dois alertas de prova perdida — BankEvidenceLost e ControlEvidenceLost, os dois com source = Attachment — não vêm de varredura: nascem do aviso do Anexo quando o veredito de um anexo de prova de controle muda depois do fechamento do dono, o registro de origem é o anexo, e só a decisão os fecha. A decisão é POST /supplier-compliance-alerts/{aid}:decide, com verify:suppliers e justificativa obrigatória; Blocked só é aceito com o fornecedor já bloqueado pela rota própria (409 SUPPLIER_COMPLIANCE_DECISION_NOT_BLOCKED_CONFLICT) — o alerta registra, o bloqueio é o ato. Lista: GET /supplier-compliance-alerts (read:suppliers, filtro por status, kind, fornecedor). Periodicidade: sanções (CEIS, CNEP, CEPIM, leniência, TCU, CNIA, OFAC) toda semana sobre os fornecedores ativos e na submissão de toda qualificação; lista suja do MTE a cada publicação; situação cadastral pelo menos a cada 30 dias (RN-FOR-24); conferência com o ERP todo dia (RN-FOR-32). Certidão vencida não é alerta: é status derivado da data, com aviso antecipado (RN-FOR-26). O aviso do alerta aberto é o de conformidade da Notificação. Sanção nunca bloqueia sozinha (RN-FOR-10).

RN-FOR-38

Contestar mudança de contato já aplicada desfaz a mudança e trava as propostas de conta

A alteração de contato aplicada — NoticeContact ou ChainContact — leva ao endereço anterior o aviso de aplicação com usableFrom e token de contestação, que vale até 30 dias depois de usableFrom, com as regras de token da RN-FOR-30 e pela mesma rota POST /portal/bank-change-contests. Contestada — pelo link ou por dentro (:contest) —, acontece na mesma transação: (1) o contato volta ao valor anterior guardado na proposta, com a origem, a data e o autor que aquele valor tinha — o relógio de confiança dele não reinicia; (2) a proposta vai a Contested e o valor novo fica não confiável: nunca é telefone confiável nem canal de aviso do fornecedor, e gravá-lo de novo em contato dele por outro caminho que não o do item 4 responde 409 SUPPLIER_CONTACT_VALUE_CONTESTED_CONFLICT; (3) o fornecedor ganha bankProposalsBlockedAt e bankProposalsBlockedByProposalId — criar ou submeter proposta BankAccount responde 409 BANK_CHANGE_SUPPLIER_CHANNEL_CONTESTED_CONFLICT, as propostas do fornecedor em Draft ou Open, de conta e de contato, são canceladas (a instância, quando há, pelo cancel do motor) e a conta aplicada depois da aplicação da mudança contestada ganha contestedAt (RN-FOR-22); (4) o bloqueio só cai com uma nova troca de canal — que pode reconfirmar o valor restaurado — decidida na instância BANK_ACCOUNT_CHANGE com a flag contestedChannel, que aciona o passo complementar da controladoria semeado no Fluxo; enquanto o bloqueio durar, também a proposta ChainContact abre essa instância, em vez de ir à confirmação da RN-FOR-34. O desfecho que aplica essa proposta limpa o bloqueio na mesma transação. Depois do commit sai supplier-bank-change-proposal.contested, com o changeKind, e o aviso obrigatório vai a quem tem approve:supplier-banks e ao administrador do tenant. Canal já comprometido suspende, não reverte: quando a mudança contestada veio de proposta com a flag contestedChannel — o fornecedor já tinha contestado antes — ou de proposta com signedRequest gravado (RN-FOR-40), os itens (1) e (2) não restauram o valor anterior: na mesma transação a mudança fica suspensa — valor anterior e valor novo, os dois, deixam de ser canal de aviso e fonte de telefone confiável —, o fornecedor ganha o bloqueio do item (3), e o caso vai ao passo complementar da controladoria, na instância BANK_ACCOUNT_CHANGE com a flag contestedChannel, que decide com a evidência qual valor vale — o anterior, o novo, ou nenhum dos dois, caso em que o fornecedor fica sem canal e aí só se sai pela RN-FOR-23. Só o desfecho dessa instância restaura um valor e limpa o bloqueio; a suspensão não cai por decurso de prazo. Por quê: contestação que só marca a proposta deixa o contato do fraudador no lugar — e é para ele que iriam o próximo aviso e o próximo callback.

RN-FOR-39

Quem o fornecedor é não muda por edição depois da aprovação

Com o cadastro Approved, entityType, cpf, ownerCpf e, em Foreign, legalName e o par foreignTaxId/taxIdCountry — o documento e o nome contra os quais a RN-FOR-13 compara o titular da conta — não mudam por PUT, tela nem importação: 409 SUPPLIER_IDENTITY_IMMUTABLE_CONFLICT. A raiz do CNPJ já é imutável desde a criação (RN-FOR-33), e nenhuma correção carrega CNPJ. O que a correção alcança: cpf de Individual e RuralProducer; ownerCpf de MEI; legalName e foreignTaxId/taxIdCountry de Foreign; e entityType só entre tipos que não mudam a existência do CNPJ — Individual ↔ RuralProducer, e Company ↔ MEI com o mesmo cnpjRoot, levando o ownerCpf quando o destino é MEI. Qualquer outra troca de tipo — entre tipo com CNPJ e tipo sem CNPJ, ou de e para Foreign — responde 422 SUPPLIER_IDENTITY_CORRECTION_TYPE_CHANGE_UNPROCESSABLE, com a orientação: é fornecedor novo, e o antigo é inativado. A ligação acompanha o sucessor: esse fornecedor novo é criado com supersedesSupplierId apontando para o antecessor inativado do mesmo tenant — um sucessor por antecessor, sem ciclo, imutável depois da criação; antecessor ativo, de outro tenant, já sucedido ou em ciclo responde 422 SUPPLIER_SUCCESSOR_NOT_ELIGIBLE_UNPROCESSABLE — e nasce com o identityCorrectionLinkedPeople do antecessor, com a mesma instância de origem e a mesma data, sem prazo (RN-FOR-41). E quem está ligado a um fornecedor inativado não cria fornecedor: POST /suppliers por pessoa ligada — pelo usuário ou pela chave de pessoa — responde 409 SUPPLIER_CREATE_IDENTITY_CORRECTION_LINKED_CONFLICT, e quem cria o sucessor é outra pessoa. Risco aceito e registrado: um terceiro que cria o sucessor sem declarar o antecessor apaga a ligação; contra isso ficam o ato registrado com o autor, a orientação desta recusa, que nomeia o campo, e o controle bancário inteiro no fornecedor novo — aviso ao canal anterior, telefone confiável, callback e quórum de pessoas distintas. Por quê: sem isso a troca de tipo de pessoa lavava a ligação — o fornecedor novo nascia sem ninguém ligado, e quem decidiu a correção propunha nele a conta do laranja. A correção é pedida por POST /suppliers/{id}:correct-identity, com update:suppliers e justificativa: grava os valores propostos em pendingIdentityCorrection — um pedido por vez, 409 SUPPLIER_IDENTITY_CORRECTION_PENDING_CONFLICT — e abre instância SUPPLIER_REGISTRATION com a flag identityCorrection, que aciona o passo complementar da controladoria semeado no Fluxo; quem pediu fica entre os excluídos (RN-AP-60 do Fluxo), e quem pede e quem decide seguem a RN-FOR-41. A decisão exige anexo comprobatório: o pedido nasce com um anexo do tipo declarado IDENTITY_CORRECTION_PROOF — dono o próprio Supplier, identificador gravado em pendingIdentityCorrection — e a instância só se conclui com ele existente e com veredito do antivírus Available; o contrato de desfecho grava, na mesma transação, o anexo, quem o anexou e quando, e quem decidiu e quando. Sem anexo liberado, devolve Refused(SUPPLIER_IDENTITY_CORRECTION_EVIDENCE_REQUIRED_CONFLICT), a decisão não é gravada e a tarefa continua ativa. O sistema não confere o conteúdo do documento, não exige assinatura nem consulta ao provedor para decidir: qual documento comprova a correção é a norma da empresa que diz, e o que fica é o rastro — a mesma regra da RN-FOR-40, com o mesmo risco aceito. Quem lê o anexo: quem tem read:suppliers, como em todo anexo de dono Supplier — vale a matriz do Anexo, e não a lista restrita dos anexos da conta e da proposta (RN-FOR-36). Risco aceito e registrado: o documento traz o CPF do titular e fica legível a todo usuário que lê fornecedor; contra isso ficam read:suppliers ser permissão de tenant, o acesso registrado na trilha do Anexo, e o anexo continuar elegível à eliminação a pedido do titular. O processo do cadastro continua Approved: a correção não reabre o cadastro nem devolve os contatos à edição livre (RN-FOR-34). Os valores propostos passam pelas validações e unicidades do cadastro no pedido e de novo no desfecho. O contrato de desfecho aplica na mesma transação e devolve Refused(SUPPLIER_IDENTITY_CORRECTION_ACCOUNT_MISMATCH_CONFLICT) se alguma conta vigente ou proposta BankAccount em Open deixaria de conferir com a identidade nova pelo regime da RN-FOR-13 do tipo de pessoa — nos tipos com documento brasileiro, o holderTaxId que deixa de conferir; em Foreign, o holderName que deixa de conferir com o legalName novo, que na submissão é flag e aqui é recusa, porque a conta já está vigente e ninguém decidiria a flag depois do fato — a conta sai antes, por proposta, e a proposta aberta é rejeitada; instância rejeitada ou cancelada limpa pendingIdentityCorrection. Por quê: se o CPF do titular muda por edição, a conta de um laranja passa a conferir com o fornecedor e a recusa da RN-FOR-13 deixa de valer.

RN-FOR-40

Troca de canal por pedido assinado exige o anexo e o rastro, não a conferência do documento

Na instância BANK_ACCOUNT_CHANGE de proposta de canal — NoticeContact ou ChainContact — com noTrustedPhone (RN-FOR-34), a decisão só acontece com o pedido de troca anexado: um anexo do tipo declarado SIGNED_CONTACT_CHANGE_REQUEST, existente, cuja dona é a própria proposta, com veredito do antivírus Available. O que o sistema exige é o anexo e o rastro. Na mesma transação da decisão que conclui a instância, o contrato de desfecho grava em signedRequest da proposta o identificador do anexo, quem o anexou e quando, e quem decidiu e quando. Faltando o anexo — nunca enviado, de outro tipo, revogado, eliminado ou sem veredito liberado —, o desfecho devolve Refused(BANK_CHANGE_SIGNED_REQUEST_REQUIRED_CONFLICT): a decisão não é gravada e a tarefa continua ativa. O que o sistema não faz: não confere assinatura digital, verificador do ITI, selo ou consulta de cartório, apostila, poderes do signatário, nem aderência do conteúdo do documento aos dados da proposta. Qual documento serve é a norma da empresa que diz, e quem decide na controladoria responde por tê-lo lido. Não há regra de documento por país: Foreign segue exatamente este caminho, sem exigência de ICP-Brasil nem de firma reconhecida. Risco aceito e registrado: documento falso, ou assinado por quem não tem poderes, passa por aqui. O que fica contra ele é o rastro preservado, a dupla custódia por pessoa (RN-FOR-36, RN-FOR-41), os sete dias de carência com contestação (RN-FOR-38) e o aviso ao canal anterior com o callback (RN-FOR-29). Por quê: conferir assinatura, selo e poderes é trabalho de pessoa, e exigi-lo como campo travava a troca para sempre — em Foreign não havia documento possível — sem tornar o documento mais verdadeiro.

RN-FOR-41

Quem pede ou decide a correção de identidade fica fora do bancário e do canal daquele fornecedor

Quem pede a correção de identidade (RN-FOR-39) e quem decide na instância dela — toda decisão, do passo do cadastro e do complementar da controladoria — precisam de identidade verificada com CPF único por tenant (RN-FOR-36). A comparação entre pessoas é pela chave de pessoa que a plataforma expõe — igual para o mesmo CPF, diferente para CPFs diferentes, sem entregar o CPF em claro (demanda P17) —: dois usuários com o mesmo CPF são uma pessoa. O :correct-identity por usuário sem identidade verificada responde 409 SUPPLIER_IDENTITY_CORRECTION_IDENTITY_NOT_VERIFIED_CONFLICT, e nada é gravado; na decisão que concluiria a instância, o contrato de desfecho devolve Refused com o mesmo código quando alguma decisão não vem de CPF verificado, quando vem da chave de pessoa de quem pediu, ou quando as decisões não são de CPFs distintos entre si — a mesma cláusula da RN-FOR-36, e é ela que impede que a base seja decidida por um usuário e a controladoria por outro do mesmo CPF, o primeiro já desativado. Essas pessoas ficam ligadas ao fornecedor: o pedido grava quem pediu e o desfecho, qualquer que seja o resultado — aprovado, rejeitado ou cancelado —, grava quem decidiu, em identityCorrectionLinkedPeople (usuário, chave de pessoa, papel, instância e a data do desfecho). A ligação não tem prazo: vale enquanto aquele fornecedor existir, e é conferida no instante de cada ato. Alcance: pessoa ligada — por usuário ou por chave de pessoa — não propõe, não confirma e não decide conta bancária nem canal de aviso daquele fornecedor: o :submit de proposta BankAccount, NoticeContact ou ChainContact, a confirmação de ChainContact, o registro de callback, o envio do pedido assinado da RN-FOR-40, a contestação por dentro (:contest, RN-FOR-30) e o envio ou a confirmação de carga inicial com linha desse fornecedor respondem 409 BANK_CHANGE_IDENTITY_CORRECTION_LINKED_CONFLICT, e nada é gravado; e o contrato de desfecho do BANK_ACCOUNT_CHANGE — de conta ou de canal — devolve Refused com o mesmo código quando alguma decisão da instância vem de pessoa ligada. No motor, a ligação entra na submissão: ao submeter proposta de conta ou de canal daquele fornecedor, o Fornecedor manda em excludedUsers (RN-AP-60 do Fluxo), com reason = IdentityCorrectionLinked, todos os usuários de cada chave de pessoa ligada — a lista é montada por chave de pessoa, não por usuário —, ao lado do proponente; o motor os remove de toda tarefa antes de qualquer outra regra, e a tarefa nunca é atribuída a quem o desfecho recusaria. Sem essa lista a ligação não teria efeito no motor: a tarefa iria ao ligado, o desfecho devolveria Refused, a tarefa continuaria ativa e ninguém seria avisado — laço, não parada. Esgotados os elegíveis, nada se afrouxa: o passo ativa parado, com awaitingEligibleApprovers e o aviso obrigatório ao administrador do tenant e à controladoria (Fluxo, RN-AP-59) — e também quando o quórum já resolve vazio na própria submissão: o BANK_ACCOUNT_CHANGE não tem reserva, e menos de duas pessoas elegíveis deixa a instância parada já na submissão, com awaitingEligibleApprovers e o mesmo aviso obrigatório. A proposta nunca volta a quem propôs, e nunca é recusada com 422: ela precisa existir para ser vista e contestada. Nada é aplicado, e o administrador sabe. Por quê: com prazo de 30 dias, no dia 31 o outro usuário de quem decidiu propunha a conta do laranja; e o canal é a porta do controle bancário — quem põe o próprio número como contato do fornecedor atende o callback 30 dias depois.

Camada API

Endpoints

Prefixo api/v{version}/nexio, [Authorize] e uma permissão explícita por endpoint. Sucesso 200, inclusive nos POST.

RotaPermissãoObservação
GET /suppliersread:suppliersPaged. Filtros: search, relacionamento, statusProcesso, bloqueado, categoryNodeId, comDocumentoVencido, faixaRisco, uf.
GET /suppliers/{id}read:suppliersCompleto, com estabelecimentos, endereços, contatos, documentos e homologações.
POST /supplierscreate:suppliersNasce em Draft / Prospect. Aceita supersedesSupplierId — o fornecedor inativado que este substitui —, e aí o novo nasce com as pessoas ligadas do antecessor; quem está ligado a fornecedor inativado não cria fornecedor (RN-FOR-39, RN-FOR-41).
PUT /suppliers/{id}update:suppliersCampos bancários rejeitados aqui — usam o fluxo de proposta. Em cadastro Approved, entityType, cpf, ownerCpf e, em Foreign, legalName e foreignTaxId/taxIdCountry respondem 409 SUPPLIER_IDENTITY_IMMUTABLE_CONFLICT; a correção é por :correct-identity (RN-FOR-39).
POST /suppliers/lookup-cnpjread:suppliersConsulta o CNPJ e devolve os dados para autopreenchimento sem gravar, junto com o resultado da checagem de duplicidade.
POST /suppliers/{id}/submitcreate:suppliersEnvia para análise: abre a instância SUPPLIER_REGISTRATION no motor e põe o cadastro em UnderReview.
sem rota própria—Aprovar e recusar o cadastro é decisão do motor, na tarefa da instância (POST /approvals/{id}/assignments/{aid}/approve · /reject). Ao terminar, o Fornecedor grava Approved ou Rejected com a quádrupla de motivo — uso SupplierReject, ver Motivo.
POST /suppliers/{id}/block · /unblockblock:suppliersMotivo codificado obrigatório nos dois sentidos — SupplierBlock e SupplierUnblock. O desbloqueio é o ato silencioso, e é o primeiro que uma auditoria de compras procura.
GET /suppliers/{id}/establishments POST PUTupdate:suppliersCNPJ validado e único.
PUT /suppliers/{id}/addresses · /contactsupdate:suppliersReescrevem o conjunto. E-mail e telefone de contato Finance ou da cadeia de reserva (PortalAdmin, Commercial designado, contato designado do estabelecimento principal) são rejeitados aqui — usam o fluxo de proposta (409 SUPPLIER_CONTACT_PROTECTED_FIELD_CONFLICT). Criar, inativar, reativar, dar ou tirar um desses papéis e designar ou retirar posição caem na mesma regra: é troca de canal por outro caminho. Antes da aprovação do cadastro esses contatos são livres (RN-FOR-34).
POST /suppliers/{id}/contacts/change-proposalspropose:supplier-banksCria em Draft a proposta de alteração de contato do aviso, na mesma entidade da proposta bancária: NoticeContact quando o contato é ou passa a ser Finance (instância BANK_ACCOUNT_CHANGE), ChainContact quando é da cadeia de reserva ou é o primeiro contato do aviso (confirmação por segunda pessoa; instância sem telefone confiável) — calculado, nunca declarado. Aviso no canal anterior. Ver RN-FOR-34. A permissão é a bancária de propósito: quem propõe canal está mexendo no controle de fraude, não no cadastro.
POST /suppliers/{id}:correct-identityupdate:suppliersPede a correção de cpf (Individual, RuralProducer), ownerCpf (MEI), legalName e foreignTaxId/taxIdCountry (Foreign) ou de entityType sem mudar a existência do CNPJ, de fornecedor aprovado, com justificativa; nunca carrega CNPJ. Quem pede tem identidade verificada e anexa o documento comprobatório (IDENTITY_CORRECTION_PROOF), que o sistema exige mas não confere. Abre instância SUPPLIER_REGISTRATION com a controladoria. Ver RN-FOR-39 e RN-FOR-41.
POST /suppliers/{id}/documentsupdate:suppliersMultipart. Tipo, número, emissão e vencimento conforme o tipo exige. supplierEstablishmentId obrigatório quando o tipo é de escopo Establishment.
GET /suppliers/{id}/document-requirementsread:suppliersResolve o pacote exigido dado categorias e faixa de risco, com o que está pendente, vencido e dispensado — por alvo: a raiz e cada estabelecimento ativo, cada um com a sua lista. Aceita ?supplierEstablishmentId= para pedir um alvo só.
POST /suppliers/{id}/verificationsverify:suppliersDispara consulta às fontes escolhidas e grava o resultado.
GET /suppliers/{id}/verificationsread:suppliersHistórico append-only.
GET /suppliers/{id}/bank-accountsread:supplier-banksPermissão própria. Números mascarados salvo read-unmasked:supplier-banks (RN-FOR-36). Devolve accountKind e usableFrom; conta em carência vem marcada como tal.
POST /suppliers/{id}/bank-accounts/change-proposalspropose:supplier-banksCria a proposta em Draft. Nunca altera o registro vivo. Ver RN-FOR-35.
PUT /suppliers/{id}/change-proposals/{pid} DELETEpropose:supplier-banksEdita ou descarta o rascunho — só o proponente, só em Draft. Depois, 409 BANK_CHANGE_PROPOSAL_IMMUTABLE_CONFLICT.
POST /suppliers/{id}/change-proposals/{pid}:submitpropose:supplier-banksSubmete: recusa proponente sem identidade verificada, fornecedor travado, titular que não confere e número que só falta por estar ligado ao proponente; faz a consulta nova ao provedor quando falta telefone; exige titularidade liberada na proposta de conta e, na troca de canal sem telefone confiável, o pedido assinado; grava dataHash, avisa e abre a instância (ou, em ChainContact fora de trava e com telefone confiável, só avisa). Ver RN-FOR-35.
POST /suppliers/{id}/change-proposals/{pid}:confirm · :rejectapprove:supplier-banksSó ChainContact: segunda pessoa confirma ou recusa; confirmar exige aviso entregue há minNoticeHours e callback Confirmed — no primeiro contato do aviso, sem endereço anterior, só o callback. Ver RN-FOR-34.
GET /suppliers/{id}/change-proposalsread:supplier-banksPropostas dos três changeKind, com status, evidência do callback, aviso e contestação. Nunca devolve token.
POST /suppliers/{id}/change-proposals/{pid}:record-callbackapprove:supplier-banksRegistra o callback, em qualquer changeKind. Telefone confiável; pessoa diferente do proponente e não ligada ao número; uma vez só. Ver RN-FOR-29.
POST /suppliers/{id}/change-proposals/{pid}:contestread:supplier-banksContestação recebida por canal independente, com nota — de conta ou de contato. Ver RN-FOR-30 e RN-FOR-38.
POST /portal/bank-change-contests— (token)Contestação pelo link do aviso — de conta ou de contato —, sem login e de uso único. Autorizada pelo token, como as demais rotas do portal. Ver RN-FOR-30 e RN-FOR-38.
POST /suppliers/bank-accounts:initial-loadpropose:supplier-banksCarga inicial de implantação. dryRun=true obrigatório antes; tudo ou nada; remetente com identidade verificada. Ver RN-FOR-31.
POST /suppliers/bank-accounts:confirm-initial-loadapprove:supplier-banksSegunda custódia: confirma lote e hash, aplica e fecha a janela.
POST /suppliers/bank-accounts:close-initial-loadapprove:supplier-banksFecha a janela de carga inicial sem carga. Não reabre.
sem rota própria—A proposta é decidida na instância BANK_ACCOUNT_CHANGE do motor; ao terminar em Approved, o Fornecedor aplica ao registro vivo e inicia a carência.
GET /suppliers/{id}/qualificationsread:suppliersA consulta de autorização de gasto da RN-FOR-24. Aceita ?categoryNodeId= e ?onDate= — quem emite pedido chama isto, não lê estado. É leitura e pede a permissão de leitura do cadastro, que quem emite pedido já tem: exigir create:supplier-qualifications ou update:supplier-qualifications aqui daria ao comprador o direito de homologar.
POST /suppliers/{id}/qualificationscreate:supplier-qualificationsHomologação por categoria. Submeter abre a instância SUPPLIER; a decisão por área é do motor.
PUT /suppliers/{id}/categoriesupdate:suppliersCategorias declaradas.
GET /suppliers/{id}/performanceread:suppliersAgregados de OTIF, atraso, divergência e aderência de preço.
GET /suppliers/{id}/auditread:supplier-auditDiff de campos e log de acesso a dado pessoal.

Contrato

Códigos de erro

CódigoHTTPQuando
SUPPLIER_NOT_FOUND404Fornecedor inexistente no tenant
SUPPLIER_CNPJ_INVALID400Formato ou dígito verificador inválido
SUPPLIER_CPF_INVALID400CPF inválido em fornecedor pessoa física
SUPPLIER_FIELD_NOT_APPLICABLE400Campo preenchido que o tipo de pessoa não usa
SUPPLIER_IE_STATE_REQUIRED400Inscrição estadual informada sem UF
SUPPLIER_PRIMARY_ESTABLISHMENT_REQUIRED400Nenhum ou mais de um estabelecimento principal
SUPPLIER_DUPLICATE_CONFLICT409CNPJ, raiz do CNPJ, CPF ou taxIdCountry + foreignTaxId já cadastrado, inclusive em rascunho ou pendente. Nome do existente exposto só a usuário interno
SUPPLIER_VERSION_CONFLICT409Versão defasada no PUT
SUPPLIER_NOT_SPEND_AUTHORIZED_CONFLICT409Pedido para fornecedor em Prospect
SUPPLIER_BLOCKED_CONFLICT409Operação em fornecedor bloqueado — mensagem traz o motivo
SUPPLIER_STATE_TRANSITION_CONFLICT409Transição de processo inválida
SUPPLIER_HAS_DOCUMENTS_CONFLICT409Exclusão de fornecedor com RFQ, pedido ou nota
SUPPLIER_REQUIRED_DOCUMENTS_MISSING_UNPROCESSABLE422Homologação sem os documentos exigidos — lista os tipos faltantes
SUPPLIER_DOCUMENT_EXPIRED_CONFLICT409Novo pedido com documento vencido de política bloqueante
SUPPLIER_REGISTRATION_STATUS_NOT_ACTIVE_UNPROCESSABLE422Homologação de fornecedor com situação cadastral diferente de Ativa
QUALIFICATION_SCOPE_REQUIRED400Homologação sem categorias no escopo
BANK_CHANGE_REQUIRES_PROPOSAL_CONFLICT409Tentativa de alterar campo bancário protegido por PUT direto
BANK_CHANGE_APPROVER_IS_REQUESTER_CONFLICT409Aprovador, autor do callback, confirmador da alteração de contato ou da carga inicial igual ao proponente ou ao remetente — mesmo usuário ou mesmo CPF verificado; autor do callback ligado ao número usado; submissão cujos únicos telefones confiáveis estão ligados ao proponente (nunca vira noTrustedPhone); também como Refused do desfecho quando decisão da instância vem do CPF de pessoa ligada ao número do callback (RN-FOR-36)
BANK_HOLDER_MISMATCH_UNPROCESSABLE422Submissão de proposta ou linha de carga inicial cujo titular não confere com o fornecedor pela comparação do tipo de pessoa (Foreign não recusa: segue com flag)
BANK_PIX_KEY_UNVERIFIED_UNPROCESSABLE422Chave aleatória sem resolução de titularidade
SUPPLIER_NOT_QUALIFIED_FOR_CATEGORY_CONFLICT409Linha de documento cuja categoria não é coberta por qualificação vigente — nomeia o nó pedido
SUPPLIER_ESTABLISHMENT_NOT_ACTIVE_CONFLICT409Pedido novo para estabelecimento inativo, com situação cadastral diferente de Active ou sem verificação — nomeia estabelecimento e situação
SUPPLIER_ESTABLISHMENT_ROOT_MISMATCH_CONFLICT409Estabelecimento cujo CNPJ tem raiz diferente da do fornecedor
SUPPLIER_PARENT_INVALID400parentSupplierId da mesma raiz, do próprio fornecedor ou formando ciclo
SUPPLIER_CONTACT_PROTECTED_FIELD_CONFLICT409Alteração de e-mail ou telefone de contato Finance ou da cadeia de reserva — ou criação, inativação e troca desses papéis — fora do fluxo de proposta
SUPPLIER_DOCUMENT_ESTABLISHMENT_REQUIRED400Documento de escopo Establishment sem supplierEstablishmentId, ou de escopo Supplier com ele
BANK_ACCOUNT_NOT_USABLE_YET_CONFLICT409Conta pedida como destino de pagamento antes de usableFrom
BANK_CHANGE_NO_EXTERNAL_NOTICE_CHANNEL_UNPROCESSABLE422Proposta bancária ou de canal sem nenhum e-mail de contato do fornecedor na cadeia da RN-FOR-21
BANK_ACCOUNT_CONTESTED_CONFLICT409Conta com contestedAt pedida como destino de pagamento
BANK_CHANGE_NOTICE_NOT_DELIVERED_CONFLICT409Desfecho recusado, ou confirmação de ChainContact recusada: não há aviso sem devolução há pelo menos minNoticeHours
BANK_CHANGE_CALLBACK_REQUIRED_CONFLICT409Desfecho recusado, ou confirmação de ChainContact recusada: proposta sem callback Confirmed para o dataHash
BANK_CHANGE_CALLBACK_ALREADY_RECORDED_CONFLICT409Callback com resultado já gravado na proposta
BANK_CHANGE_CALLBACK_PHONE_NOT_TRUSTED_UNPROCESSABLE422Número do callback que não é telefone confiável: contato inativo, fora de Finance e das três posições da cadeia, com menos de 30 dias desde o mais tarde entre a gravação e a entrada do contato em Finance ou na cadeia, ou ligado ao proponente; ou telefone que não é o da consulta mais recente ao CNPJ pelo provedor, ou que mudou desde a consulta anterior há menos de 30 dias
BANK_CHANGE_OWNERSHIP_EVIDENCE_REQUIRED_CONFLICT409Submissão de proposta de conta sem comprovante de titularidade liberado
BANK_CHANGE_PROPOSAL_IMMUTABLE_CONFLICT409Edição ou descarte de proposta já submetida, nas rotas do Fornecedor — nas rotas de anexo o código é do Anexo, ATTACHMENT_OWNER_NOT_WRITABLE_CONFLICT
SUPPLIER_CONTACT_CHANGE_WINDOW_NOT_ELAPSED_CONFLICT409Confirmação de alteração protegida de contato antes de minNoticeHours do aviso
SUPPLIER_VERIFICATION_BY_PROPONENT_CONFLICT409Verificação manual de CNPJ registrada por quem é proponente de proposta do fornecedor em Draft ou Open
BANK_INITIAL_LOAD_EVIDENCE_MISSING_CONFLICT409Confirmação de lote com linha sem evidência utilizável: sem comprovante e sem callback confirmado, ou comprovante revogado, eliminado, Infected, em estado reprovado, com veredito Failed, ou em reserva Reserved ainda confirmável. Lista as linhas e o estado de cada uma. Sem falta, comprovante ainda em varredura (Pending ou Scanning) responde o ATTACHMENT_SCAN_PENDING_CONFLICT do Anexo (RN-FOR-31)
SUPPLIER_STATE_REGISTRATION_DUPLICATE_CONFLICT409Segundo estabelecimento de produtor rural com a mesma IE (UF + número)
SUPPLIER_COMPLIANCE_DECISION_NOT_BLOCKED_CONFLICT409Decisão Blocked em alerta de fornecedor que não está bloqueado
BANK_CHANGE_PROPOSAL_NOT_CONTESTABLE_CONFLICT409Contestação interna de proposta Rejected, Cancelled ou Contested
BANK_CHANGE_CONTEST_TOKEN_INVALID_UNAUTHORIZED401Token de contestação desconhecido, usado ou vencido — a resposta não distingue os três
BANK_INITIAL_LOAD_WINDOW_CLOSED_CONFLICT409Carga inicial com a janela fechada
BANK_INITIAL_LOAD_SUPPLIER_HAS_ACCOUNT_CONFLICT409Linha de carga inicial para fornecedor que já tem conta ou proposta aberta
BANK_INITIAL_LOAD_HASH_MISMATCH_CONFLICT409Confirmação de lote com hash diferente do enviado
SUPPLIER_CONTACT_CHANGE_NO_TRUSTED_PHONE_UNPROCESSABLE422Submissão de NoticeContact ou ChainContact sem telefone confiável — nenhum contato ativo Finance ou da cadeia com número confiável — 30 dias contados do mais tarde entre a gravação e a entrada do contato em Finance ou na cadeia —, nem telefone confiável na consulta nova ao provedor — e sem anexo SIGNED_CONTACT_CHANGE_REQUEST com veredito Available
BANK_CHANGE_REGISTRY_LOOKUP_UNAVAILABLE503Submissão que precisa da consulta nova ao provedor para decidir se há telefone confiável, com o provedor indisponível — repetir depois
SUPPLIER_CONTACT_VALUE_CONTESTED_CONFLICT409E-mail ou número de mudança de contato contestada gravado de novo no fornecedor fora da troca de canal com a controladoria
BANK_CHANGE_SUPPLIER_CHANNEL_CONTESTED_CONFLICT409Criação ou submissão de proposta de conta de fornecedor com propostas travadas por contestação de contato
BANK_APPROVER_IDENTITY_NOT_VERIFIED_CONFLICT409Ação de approve:supplier-banks por usuário sem identidade verificada; também como Refused do desfecho quando as decisões não vêm de CPFs verificados, distintos entre si e do proponente
BANK_PROPOSER_IDENTITY_NOT_VERIFIED_CONFLICT409Submissão de proposta — de conta ou de contato — ou envio de carga inicial por usuário sem identidade verificada com CPF único por tenant (RN-FOR-36)
BANK_CHANGE_EVIDENCE_NOT_AVAILABLE_CONFLICT409Desfecho recusado: o comprovante de titularidade ou o pedido assinado exigido na submissão foi revogado, eliminado ou deixou de estar Available (RN-FOR-35)
SUPPLIER_IDENTITY_IMMUTABLE_CONFLICT409entityType, cpf, ownerCpf ou, em Foreign, legalName, foreignTaxId ou taxIdCountry alterado por PUT, tela ou importação em cadastro Approved (RN-FOR-39)
SUPPLIER_IDENTITY_CORRECTION_PENDING_CONFLICT409Pedido de correção de identidade com outro ainda em aprovação
SUPPLIER_IDENTITY_CORRECTION_ACCOUNT_MISMATCH_CONFLICT409Desfecho da correção de identidade recusado: conta vigente ou proposta de conta Open deixaria de conferir com o titular novo (RN-FOR-39)
SUPPLIER_IDENTITY_CORRECTION_TYPE_CHANGE_UNPROCESSABLE422Correção de identidade que troca entityType fora de Individual ↔ RuralProducer e de Company ↔ MEI com o mesmo cnpjRoot: é fornecedor novo, e o antigo é inativado (RN-FOR-39)
SUPPLIER_IDENTITY_CORRECTION_IDENTITY_NOT_VERIFIED_CONFLICT409Pedido de correção de identidade por usuário sem identidade verificada; também como Refused do desfecho quando alguma decisão não vem de CPF verificado ou vem do CPF de quem pediu (RN-FOR-41)
BANK_CHANGE_IDENTITY_CORRECTION_LINKED_CONFLICT409Submissão de proposta de conta ou de canal, confirmação de ChainContact, registro de callback, envio do pedido assinado, contestação por dentro, envio ou confirmação de carga inicial por pessoa — usuário ou chave de pessoa — ligada a correção de identidade daquele fornecedor, sem prazo; também como Refused do desfecho do BANK_ACCOUNT_CHANGE de conta ou de canal (RN-FOR-41)
SUPPLIER_CREATE_IDENTITY_CORRECTION_LINKED_CONFLICT409Criação de fornecedor por pessoa — usuário ou chave de pessoa — ligada a correção de identidade de fornecedor inativado: quem cria o sucessor é outra pessoa (RN-FOR-39)
SUPPLIER_SUCCESSOR_NOT_ELIGIBLE_UNPROCESSABLE422supersedesSupplierId de fornecedor ativo, de outro tenant, que já tem sucessor, ou que forma ciclo (RN-FOR-39)
SUPPLIER_CONTACT_CONTEST_IDENTITY_NOT_VERIFIED_CONFLICT409Registro ou confirmação de contestação por dentro do Nexio por usuário sem identidade verificada; as duas pontas precisam dela (RN-FOR-30, RN-FOR-36)
BANK_CHANGE_SIGNED_REQUEST_REQUIRED_CONFLICT409Desfecho recusado: troca de canal com noTrustedPhone sem o anexo SIGNED_CONTACT_CHANGE_REQUEST da proposta liberado pelo antivírus — nunca enviado, de outro tipo, revogado, eliminado ou sem veredito (RN-FOR-40)
SUPPLIER_IDENTITY_CORRECTION_EVIDENCE_REQUIRED_CONFLICT409Desfecho recusado: correção de identidade sem o anexo IDENTITY_CORRECTION_PROOF liberado pelo antivírus. O conteúdo do documento não é conferido (RN-FOR-39)
SUPPLIER_CONTACT_CONTEST_SECOND_PERSON_REQUIRED_CONFLICT409Contestação por dentro do Nexio confirmada pela mesma pessoa que a registrou — mesmo usuário ou mesma chave de pessoa —, ou ainda sem a segunda pessoa (RN-FOR-30)

Autorização

Permissões

PermissãoCobre
read:suppliers · create:suppliers · update:suppliers · delete:suppliersCRUD do cadastro. read:suppliers cobre também a consulta de autorização de gasto (GET /suppliers/{id}/qualifications, RN-FOR-24) — é leitura, e quem emite pedido precisa dela
approve:suppliersAlvo da política padrão de SUPPLIER_REGISTRATION — quem a tem recebe as tarefas de aprovação do cadastro no motor
block:suppliersBloquear e desbloquear
verify:suppliersDisparar consultas a fontes oficiais
create:supplier-qualificationsSubmeter a homologação por categoria (POST /suppliers/{id}/qualifications), que abre a instância SUPPLIER. Consultar a qualificação não pede esta permissão — o GET é de read:suppliers
update:supplier-qualificationsConduzir a homologação, manter questionários e requisitos de documento; alvo da política padrão de SUPPLIER. Consultar a qualificação não pede esta permissão — o GET é de read:suppliers. [PERGUNTA AO ROGER: o alvo da política padrão de SUPPLIER (quem decide por área no painel) é update:supplier-qualifications ou cabe um approve:supplier-qualifications, como em approve:suppliers e approve:supplier-banks? Decidir pede um verbo fora dos cinco.]
read:supplier-banksVer dados bancários — números mascarados por padrão
read-unmasked:supplier-banksVer agência, conta, chave PIX e IBAN sem máscara, e os anexos da conta e da proposta (lista completa de leitura na RN-FOR-36). Concessão é ato de controle, com aviso (RN-FOR-36)
propose:supplier-banksSolicitar alteração bancária e alteração do canal de aviso (e-mail e telefone dos contatos Finance e da cadeia de reserva) — os dois são o mesmo controle; exige identidade verificada com CPF único por tenant (RN-FOR-36)
approve:supplier-banksAlvo da política semeada de BANK_ACCOUNT_CHANGE, em toda proposta que abre a instância — de conta, NoticeContact e ChainContact sem telefone confiável ou em trava — quem a tem recebe as tarefas no motor, registra o callback, confirma a carga inicial e a alteração protegida de contato; exige identidade verificada com CPF único por tenant, e concedê-la gera aviso obrigatório, inclusive ao contato contratual do tenant (RN-FOR-36); a semente do processo está no Fluxo de Aprovação. Não deve estar no mesmo perfil de propose; e update:suppliers sozinho não muda canal de aviso, que é o buraco que a RN-FOR-21 fecha
read:supplier-auditHistórico e log de acesso a dado pessoal

Grupos sugeridos: Nexio - Fornecedores (read/create/update), Nexio - Homologação (+ approve, verify, qualification), Nexio - Tesouraria (read:supplier-banks + approve:supplier-banks, sem propose) e Nexio - Consulta (read). A separação entre quem propõe e quem aprova mudança bancária é a razão de existirem duas permissões.

Privacidade

LGPD

CNPJ não é dado pessoal. CPF de sócio, contato e fornecedor pessoa física são — e é aí que a lei incide.

SituaçãoBase legal sugerida
Dados de fornecedor pessoa física (Individual, RuralProducer, ownerCpf do MEI) para contratar, pedir e pagarArt. 7º, V — execução de contrato e procedimentos preliminares a pedido do titular
Contato de pessoa jurídica (nome, e-mail, telefone de quem representa o fornecedor)Art. 7º, IX — legítimo interesse do comprador em se relacionar com a empresa, com teste de balanceamento documentado. O contato não é parte do contrato: a empresa é
Guardar documento fiscal, pedido e prova de pagamentoArt. 7º, II — obrigação legal (guarda fiscal)
Exigir certidões e fazer due diligence de integridadeArt. 7º, IX — legítimo interesse. No setor privado não há lei que obrigue o comprador a exigir certidão; onde um regulador setorial obrigar, vale o inciso II para aquele caso
Callback, aviso e contestação da troca de conta; conferência com o ERPArt. 7º, IX — legítimo interesse em prevenção a fraude. Consentimento não é condição (RN-FOR-29)

Quem é controlador e quem é operador

O tenant é o controlador: decide cadastrar, exigir documento e reter. O Nexio é operador, e os provedores que ele usa — consulta ao CNPJ, envio de e-mail, armazenamento — são suboperadores listados no contrato. Pedido de titular chega ao controlador; o produto dá a ele a ferramenta (exportar, anonimizar), e o suporte do Nexio não atende titular por conta própria.

Prazos de guarda, semeados e só alongáveis

Contato de fornecedor que nunca cotou nem recebeu pedido: anonimizado 2 anos depois da última atividade. Contato e dados de pessoa física de fornecedor com relação: enquanto a relação durar e 5 anos depois do último documento fiscal. Proposta bancária, evidência de callback, titularidade e contestação: 5 anos depois do encerramento da conta ou da proposta. Verificação e alerta de sanção: 5 anos. Certidão cível ou criminal de sócio: enquanto a qualificação que a exigiu estiver vigente. Log de acesso a dado pessoal: 1 ano (mínimo legal de 6 meses, Marco Civil, art. 15). O tenant alonga, nunca encurta; retenção legal em curso vence eliminação. Confirmar os prazos com o encarregado antes de produção.

Consentimento é a base errada aqui

É o erro clássico. Se o fornecedor pode revogar a qualquer momento, o comprador perde a base para manter dados que precisa reter por obrigação legal.

Isole os dados pessoais em tabelas próprias, com retenção própria

SupplierContact — e a entidade de sócio, se o quadro societário entrar (pendência d) — tem ciclo de vida independente do cadastro da empresa. Contato de fornecedor que nunca fechou negócio não pode ficar para sempre.

Eliminação é anonimização parcial, não delete

Apague o contato pessoal e preserve o registro transacional pseudonimizado necessário à auditoria. Um delete que apaga o histórico de compras cria problema fiscal maior do que resolve.

Certidões cíveis e criminais de sócios são o ponto mais sensível

Coleta indiscriminada de antecedentes de todos os fornecedores dificilmente passa num teste de necessidade e proporcionalidade. Torne opcional, por faixa de risco alta, com justificativa registrada — nunca padrão do sistema.

Fornecedor pessoa física muda o tratamento inteiro

Ali o cadastro da "empresa" é cadastro de pessoa natural. Retenção, acesso e eliminação seguem regra diferente — isso justifica um caminho próprio no código, não um if.

Base compartilhada entre tenants é ótima em UX e é onde mora o risco

Reaproveitar o cadastro que um fornecedor já preencheu para outro comprador é o principal argumento comercial dos SRMs de homologação — e exige base legal explícita e transparência ao fornecedor. Se for construído, é decisão jurídica antes de ser decisão de produto.

Limites

Fora de escopo e pendências

É do ERP financeiro
  • Título a pagar, aging, provisão, saldo em aberto. O Nexio pode exibir por integração; não é fonte da verdade.
  • Cálculo de retenções (IRRF, INSS, ISS, CSRF), códigos de DARF, alíquotas. O Nexio carrega os insumos — regime tributário, IE, IM, natureza do serviço; quem calcula é o ERP fiscal. Resista ao pedido de incluir "só o campo de retenção": ele nunca vem sozinho.
  • Conta contábil do fornecedor, plano de contas, conta de reconciliação.
  • Calendário de vencimento, juros, multa e desconto. O prazo negociado é do Nexio; o cálculo é financeiro.
  • Escrituração: EFD-Reinf, DCTFWeb, SPED, comprovantes de retenção.
  • Remessa e retorno CNAB, conciliação bancária, arquivo de pagamento.
  • Limite de crédito e campos de 1099 e afins, herdados de produtos americanos.
Fora agora, previsto no modelo
  • Site comercial do fornecedor — condição de pagamento e moeda por unidade de relacionamento. Hoje ficam no estabelecimento.
  • Ponto de entrega específico no ItemSupplier — o eixo ship-to da ASL na granularidade do site. A UF de destino já está na chave do preço; o que continua fora é o preço por ponto, que é negociação e mora no ContractItem.
  • v2 — autocadastro pelo fornecedor: estado AwaitingSupplier, convite de cadastro (POST /suppliers/invite) e autodeclaração de categoria. Na v1 o cadastro é do comprador, e o Portal do Fornecedor cobre cotação, não cadastro.
  • v2 — pagamento a terceiro (cessão de crédito, factoring, FIDC). Na v1 o titular da conta é o próprio fornecedor (RN-FOR-13); pagamento a terceiro, enquanto não existir, é tratado no ERP, nunca pela conta do cadastro.
  • v2 — fornecedor eventual e promoção manual (isOneTimeSupplier, POST /suppliers/{id}/promote). Na v1 gasto só é autorizado por qualificação vigente na categoria (RN-FOR-24), e nenhum dos dois passaria por ela: seriam recurso morto ou atalho do controle.
  • Scorecard com avaliação humana — as métricas calculadas vêm primeiro.
  • Integração cXML / punchout — projeto próprio, não campo de cadastro.
  • Consulta automatizada a CND/CPEN, CRF do FGTS e CNDT — nenhuma das três tem API pública; todas são cobertas por serviços comerciais. Na v1 são entrada manual com vigência (RN-FOR-26). v2, pelo gancho de provedor plugável que na v1 já serve à consulta ao CNPJ — acrescentar ou trocar provedor não muda a spec.

Pendências para decidir. A fonte da consulta ao CNPJ e a guarda do dado bancário estão resolvidas no corpo — ver Verificações e a RN-FOR-32. (c) Base compartilhada de fornecedores entre tenants — decisão jurídica antes de produto. (d) Contatos e sócios: o quadro societário vem da Receita e é dado pessoal; entra no MVP ou fica para quando houver due diligence formal?

Registro

Histórico de revisões

VersãoDataO que mudou
v3.1030/10/2026Permissões padronizadas em read/lookup/create/update/delete (decisão de 30/10/2026). Mapeamento aplicado, por ação: manage:supplier-qualifications → create:supplier-qualifications (submeter a homologação, POST …/qualifications) e update:supplier-qualifications (conduzir, questionários e requisitos de documento; alvo da política padrão de SUPPLIER, com pergunta aberta ao Roger sobre o alvo). O GET …/qualifications segue em read:suppliers. Nenhuma regra de negócio mudou.
v3.920/09/2026Correção da validação de 18/09 (achado 18a). O campo receiptTolerance do estabelecimento passa a nomear também a política de entrega antecipada (Warn | Block, default Warn) e a dizer que o estabelecimento é o nível mais geral da precedência, herdado campo a campo pela relação e pela linha. O detalhamento continua na Unidade de Medida, que agora define o objeto.
v3.820/09/2026Correção da validação de 18/09 (achado 15a, completado na base). Endpoints: a linha de /suppliers/{id}/qualifications se divide em duas — o GET, que é a consulta de autorização de gasto da RN-FOR-24, passa a pedir read:suppliers, e só o POST continua em manage:supplier-qualifications. Permissões: as duas linhas dizem o corte. Antes, quem emitia pedido precisava de uma permissão de escrita — a de homologar — para fazer a consulta que a RN-FOR-24 exige, ou leria o estado por fora, que é o que a regra proíbe.
v3.720/09/2026Recuos da validação de 18/09 (achados 11, 15b e 15c). O que cada estado libera: a nota da tabela passa a dizer que o código de erro do convite recusado é da spec da Cotação e que o acesso do convidado ao portal, inclusive o do fornecedor bloqueado, é do Portal do Fornecedor. RN-FOR-07: como RequireJustification é exigida e registrada no pedido é da spec do Pedido; o enum fica. Item × Fornecedor (achados 13 e 14): o enum do ItemSupplier.status deixa de ser repetido aqui e passa a ser citado do Cadastro de Item; bloquear o fornecedor não reescreve as relações — o efeito é lido pelo eixo Bloqueio.
v3.613/09/2026Correção da validação R7 (antifraude). Uma porta só quando esgotam os elegíveis: a RN-FOR-41 deixa de oferecer a alternativa de recusa da submissão com devolução da proposta ao proponente e passa a citar só a parada com alerta — awaitingEligibleApprovers e aviso obrigatório ao administrador do tenant e à controladoria —, inclusive quando o quórum já resolve vazio na submissão, como o Fluxo e a semente do BANK_ACCOUNT_CHANGE escrevem. Devolver daria ao proponente uma tentativa nova sem alertar ninguém.
v3.512/09/2026Correção da validação R6 (controle e antifraude). A ligação da correção de identidade passa a ter efeito no motor: as pessoas ligadas entram em excludedUsers na submissão de proposta de conta e de canal, por chave de pessoa, com reason = IdentityCorrectionLinked; esgotados os elegíveis, o passo ativa parado com alerta (RN-FOR-35, RN-FOR-41). A ligação acompanha o sucessor: supersedesSupplierId na criação faz o fornecedor novo nascer com as pessoas ligadas do antecessor inativado, e quem está ligado não cria fornecedor (SUPPLIER_CREATE_IDENTITY_CORRECTION_LINKED_CONFLICT, SUPPLIER_SUCCESSOR_NOT_ELIGIBLE_UNPROCESSABLE; RN-FOR-39). Contestação por dentro: identidade verificada nas duas pontas (SUPPLIER_CONTACT_CONTEST_IDENTITY_NOT_VERIFIED_CONFLICT) e read:supplier-banks entre as permissões cuja concessão é ato de controle (RN-FOR-30, RN-FOR-36). O rastro que sustenta o risco aceito ganha alerta: pedido assinado e comprovante de correção de identidade que caem depois da aplicação abrem SupplierComplianceAlert de kind = ControlEvidenceLost e source = Attachment, com suspensão do canal ou da conta até a decisão (RN-FOR-35, RN-FOR-37). Estados do lote: lista completa e final da falta de evidência — Scanning conta como espera, a reserva Reserved ainda confirmável como falta, e Failed é falta, não espera (RN-FOR-31). Nomes: o tipo de anexo da correção de identidade passa a ser IDENTITY_CORRECTION_PROOF, o nome do catálogo do Anexo. Leitura desse comprovante: vale a matriz geral de anexo de dono Supplier, read:suppliers, com o risco aceito registrado. Resíduo: a RN-FOR-34 não fala mais em conferência gravada.
v3.412/09/2026Correção da validação R5 (antifraude e controle). O sistema exige o anexo e o rastro, não confere o documento: a troca de canal sem telefone confiável e a correção de identidade passam a exigir anexo do tipo declarado, liberado pelo antivírus, e a gravar anexo, quem anexou, quem decidiu, data e hora; saem a conferência da assinatura, o campo signatureCheck e o código BANK_CHANGE_SIGNATURE_CHECK_REQUIRED_CONFLICT, e entram signedRequest, BANK_CHANGE_SIGNED_REQUEST_REQUIRED_CONFLICT, IDENTITY_CORRECTION_PROOF e SUPPLIER_IDENTITY_CORRECTION_EVIDENCE_REQUIRED_CONFLICT; nenhuma regra de documento por país, e o risco aceito fica registrado (RN-FOR-39, RN-FOR-40). Ligação da correção de identidade sem prazo e cobrindo o canal: sai linkedUntil; quem pede e quem decide ficam ligados enquanto o fornecedor existir e não propõem, confirmam nem decidem conta bancária nem canal de aviso dele; o desfecho passa a exigir também CPFs distintos entre si (RN-FOR-41). Contestação de canal já comprometido suspende, não reverte, e vai ao complementar da controladoria; contestar por dentro do Nexio exige segunda pessoa (SUPPLIER_CONTACT_CONTEST_SECOND_PERSON_REQUIRED_CONFLICT; RN-FOR-30, RN-FOR-38). Comprovante: estado reprovado conta como falta no lote, e prova revogada, eliminada ou Infected depois da aplicação abre alerta BankEvidenceLost e tira a conta do pagamento até a decisão (RN-FOR-31, RN-FOR-35, RN-FOR-37). LGPD: as pessoas ligadas e o pedido de correção passam a guardar chave de pessoa, nunca o CPF em claro (demanda P17). Resíduo: em Foreign, o desfecho da correção recusa pelo regime da RN-FOR-13 daquele tipo.
v3.311/09/2026Correção da validação R4 (antifraude e dinheiro). Pedido assinado conferido: a decisão de aprovar da controladoria grava a conferência da assinatura — meio (verificador do ITI ou selo do cartório), signatário com poderes e aderência ao dataHash — em signatureCheck; sem ela, Refused(BANK_CHANGE_SIGNATURE_CHECK_REQUIRED_CONFLICT) (RN-FOR-40, nova). Correção de identidade: quem pede e quem decide têm identidade verificada, comparada por CPF, e ficam ligados ao fornecedor até 30 dias depois do desfecho, sem propor nem aprovar conta dele (identityCorrectionLinkedPeople; SUPPLIER_IDENTITY_CORRECTION_IDENTITY_NOT_VERIFIED_CONFLICT, BANK_CHANGE_IDENTITY_CORRECTION_LINKED_CONFLICT; RN-FOR-41, nova); a correção alcança cpf, ownerCpf, legalName e foreignTaxId/taxIdCountry de Foreign, e troca de tipo só sem mudar a existência do CNPJ (422 SUPPLIER_IDENTITY_CORRECTION_TYPE_CHANGE_UNPROCESSABLE); legalName e foreignTaxId/taxIdCountry de Foreign imutáveis depois da aprovação (RN-FOR-39). Decisores do BANK_ACCOUNT_CHANGE: todos, controladoria incluída, com identidade verificada; o desfecho recusa decisão de pessoa ligada ao número do callback (RN-FOR-36). Carga inicial: comprovante revogado ou eliminado vale como falta, varredura pendente é o 409 do Anexo; proposta InitialLoad responde StateOf = InProgress; lista literal de quem lê o comprovante (RN-FOR-31, RN-FOR-36). Canal devolvido sem telefone confiável segue a troca por pedido assinado (RN-FOR-23). Resíduos: imutabilidade de identidade na linha de PUT /suppliers/{id}; texto do erro de telefone; contagem de respostas do descritor.
v3.211/09/2026Correção da validação R3 (antifraude e dinheiro). Relógio de confiança do telefone conta do mais tarde entre a gravação e a entrada do contato em Finance ou na cadeia (noticeChainSince, noticeChainProposalId); telefone do provedor que mudou desde a consulta anterior só vale 30 dias depois. Número ligado ao proponente recusa a submissão (409) e nunca vira noTrustedPhone. Contato livre só antes da aprovação; o primeiro contato do aviso de cadastro aprovado é ChainContact com callback ao telefone do provedor. Cadeia de reserva com três posições (noticeChainSlot: Commercial designado e contato designado do estabelecimento principal); os demais Commercial são livres (EV-19). Troca de canal sem telefone confiável vai à instância com controladoria, SIGNED_CONTACT_CHANGE_REQUEST e 7 dias de carência (EV-18). Identidade verificada também de quem propõe e de quem envia a carga, separação por CPF (EV-21, BANK_PROPOSER_IDENTITY_NOT_VERIFIED_CONFLICT). Prova de pé no desfecho (BANK_CHANGE_EVIDENCE_NOT_AVAILABLE_CONFLICT); lista única de quem lê os anexos (RN-FOR-36); anexo em proposta imutável responde o código do Anexo; carga inicial liga remetente e confirmador ao número e confere o veredito dos comprovantes; contestação cancela também propostas de contato. RN-FOR-39: entityType, cpf e ownerCpf imutáveis depois da aprovação, correção por instância com a controladoria (ET7-3). Resíduos B17, B18 e ET9-1.
v3.111/09/2026Correção da validação R2 (antifraude). Telefone do callback só de contato ativo Finance ou da cadeia de reserva, com 30 dias, ou da consulta mais recente ao provedor; contato técnico ou de qualidade não é fonte; número ligado ao proponente não serve; noTrustedPhone só depois de consulta nova ao provedor (503 BANK_CHANGE_REGISTRY_LOOKUP_UNAVAILABLE) (RN-FOR-29). Troca de canal sem telefone confiável recusada (422 SUPPLIER_CONTACT_CHANGE_NO_TRUSTED_PHONE_UNPROCESSABLE); ChainContact criado pela mesma rota da NoticeContact, com tipo calculado, confirmação com aviso entregue e callback, confirmedByUserId, carência usableFrom e contato ligado à proposta (*ChangeProposalId) (RN-FOR-34). RN-FOR-38: contestação de mudança de contato aplicada reverte, marca o valor como não confiável e trava propostas de conta até troca com a controladoria (bankProposalsBlockedAt, flag contestedChannel). Titular ≠ fornecedor recusado na submissão, só Foreign com flag (BANK_HOLDER_MISMATCH_CONFLICT vira 422 BANK_HOLDER_MISMATCH_UNPROCESSABLE); pagamento a terceiro é v2 (RN-FOR-13). Concessão bancária avisa o contato contratual do tenant; approve:supplier-banks exige identidade verificada com CPF único (BANK_APPROVER_IDENTITY_NOT_VERIFIED_CONFLICT) (RN-FOR-36, RN-FOR-31). Importação Propose cria rascunho; verificação manual vedada também a proponente de rascunho; comprovante no tipo BANK_OWNERSHIP_PROOF, dono na carga inicial = proposta da linha. isPortalAdmin sai (é papel). Resíduos: RN-FOR-12, autodeclaração, ContractItem.
v3.011/09/2026Validação de 10/09 e correção pós-validação da onda 1. Antifraude bancário: núcleo protegido não configurável e importação só Propose/Reject (RN-FOR-28); aviso só por e-mail, sem SMS/WhatsApp; callback de saída para telefone confiável — contato gravado há 30 dias ou consulta ao CNPJ pelo provedor — com separação de pessoas e noTrustedPhone (RN-FOR-29); contestação por link de uso único com token no corpo (RN-FOR-30); carga inicial com janela única, dupla custódia, contatos e evidência por conta (RN-FOR-31); conferência diária com o ERP (RN-FOR-32); contatos da cadeia do aviso por alteração protegida (RN-FOR-34); proposta em rascunho, titularidade antes da submissão, imutável e sem devolução, evidências amarradas ao dataHash (RN-FOR-35); read-unmasked:supplier-banks e concessão como ato de controle (RN-FOR-36). Janela pelo gancho activationNotBefore e e-mail devolvido não inicia a janela (RN-FOR-23); semente do BANK_ACCOUNT_CHANGE só no Fluxo, processo sem valor; sai o gancho supplier-spend-12m e o erro BANK_CHANGE_NOTICE_WINDOW_NOT_ELAPSED_CONFLICT. Identidade: cnpjRoot varchar(8) único por tenant, grupo econômico só por parentSupplierId (RN-FOR-33); matriz/filial pelo identificador da Receita; ownerCpf do MEI; produtor rural com um estabelecimento por propriedade, IE e CAEPF. Pedido novo exige estabelecimento apto, com verificação de até 45 dias (RN-FOR-24). Consulta ao CNPJ e certidões por gancho de provedor (dados abertos na v1; CND/CRF/CNDT automáticas na v2). Conta ganha estabelecimento, moeda e padrão; proposta aponta a conta alvo. SupplierComplianceAlert com fontes TCU e CNIA e periodicidade (RN-FOR-37). LGPD: incisos corrigidos, controlador e operador, prazos de guarda. v2: autocadastro (AwaitingSupplier, convite, autodeclaração), isOneTimeSupplier e promoção manual. Falência passa à raiz; contagem de tipos por estabelecimento corrigida; resíduo do ItemSupplier (freightTerms, ItemSupplierUom).
v2.7 – v2.909/09/2026Leva de segurança da validação de 08/09 (RN-FOR-21 a RN-FOR-27): canal do aviso como campo protegido, usableFrom, janela mínima, comparação de titular por tipo de pessoa, gasto autorizado por qualificação vigente, documento por estabelecimento, certidões sem fonte automatizada, bloco bancário internacional. UF de destino passa a ser dimensão do preço (ItemSupplierPrice), não da relação.
v2.504/09/2026Toda aprovação do módulo vira instância do motor (SUPPLIER_REGISTRATION, SUPPLIER, BANK_ACCOUNT_CHANGE); saem POST /suppliers/{id}/approve · /reject e POST /bank-change-proposals/{id}/approve · /reject.
v2.404/09/2026Identidade por tipo de pessoa e estabelecimento para todo tipo (achado A7 da contra-análise); RegistrationStatus alinhado ao Establishment comprador.
até v2.3até 02/09/2026Dois níveis (Supplier e estabelecimento), CNPJ alfanumérico, Prospect/SpendAuthorized, proposta de alteração bancária, homologação por categoria; UF de destino entra na chave do par item × fornecedor (02/09/2026).