> ## Documentation Index
> Fetch the complete documentation index at: https://docs.somosunit.com.br/llms.txt
> Use this file to discover all available pages before exploring further.

# Changelog

> Novidades e mudanças na API de Parceiros da Unit

<Update label="14 de agosto de 2026" description="PAN/Crefaz no sandbox, re-simulação, margem em employers[] e correções de doc">
  ### Sandbox: PAN e Crefaz liberados + re-simulação por parâmetros

  * **Banco PAN e Crefaz entraram no allowlist do sandbox.** CPFs de teste
    novos (os anteriores tinham dígito verificador inválido e foram
    substituídos): `50077799976` (PAN — autorização WhatsApp pendente, com
    link `wa.me`), `40066688809` (PAN — consulta ok), `30055577741` (Crefaz —
    SMS DataPrev pendente, sem link), `20044466684` (Crefaz — consulta ok).
  * **Re-simulação no sandbox**: `prazo`, `loan_value` e `valor_parcela`
    agora alteram os números das ofertas, como em produção. O cenário de cada
    CPF é o teto (valor = margem máxima, parcelas = prazo máximo); pedido
    acima volta clampado com `adjusted`/`adjustments`. Modelo linear
    simplificado — homologa fluxo e teto, não precificação.

  ### Consulta

  * **`employers[].margin`**: a margem consignável apurada em tempo real na
    consulta, normalizada em número (Unit e Facta informam hoje; `null` nos
    demais). O array traz `{cnpj, name, matricula, provider, margin}`.
  * **`adjusted`/`adjustments` por oferta**: ajuste de prazo/valor sinalizado
    — inclusive o caso "pedi 36x, voltou 18x", que antes passava sem flag.
  * **`providers` com typo agora é 422**: nenhum nome válido na interseção
    com o allowlist devolve `422 invalid_input` (`field: providers`) listando
    os bancos do seu contrato, em vez de `200` com `providerResults` vazio.

  ### Correção de documentação — submit PAN/Crefaz pré-autorização

  As notas de 27/07 diziam que submit antes da autorização concluída voltava
  `provider_unavailable`/`retryable: true`. **O comportamento real é `422
      invalid_input`** apontando `offer_ref.offer_id`: aguarde o webhook
  `authorization_result` (ou re-consulte) e submeta com o `offerId` novo. As
  notas antigas abaixo foram corrigidas.
</Update>

<Update label="13 de agosto de 2026" description="Fluxo WhatsApp: link de autorização com colheita de evidência">
  ### Autorização com colheita de evidência — atendimentos 100% WhatsApp

  Zipdin, Unit e Facta exigem evidência de autorização do titular (IP, geo,
  dispositivo) — que uma conversa de WhatsApp não tem como colher. Agora a API
  resolve isso de ponta a ponta:

  * `POST /partners/v1/authorizations` gera um **link de autorização** (72h,
    idempotente por CPF); o cliente abre a página compacta, lê o termo LGPD e
    autoriza com um toque — IP (capturado no servidor), geolocalização,
    dispositivo e versão do termo ficam registrados na Unit.
  * Webhook **`authorization.completed`** avisa sua integração (ou poll no
    `GET /authorizations/{id}`, que devolve a evidência completa).
  * As rotas de consulta aceitam **`authorization_id`** no lugar de
    `client_ip`: a evidência é injetada no servidor — sua integração nunca
    transita IP/geo do cliente.

  Testável de ponta a ponta no sandbox (o aceite do cliente pode ser simulado
  por API). Pasta nova na collection do Postman com os 5 passos.
</Update>

<Update label="12 de agosto de 2026" description="Fluxo de leilão: lookup da proposta por proposal_key">
  ### Leilão — recupere a proposta e os dados do cliente pela `proposal_key`

  Novo endpoint `GET /partners/v1/auction-proposals/{proposal_key}`: quando o
  cliente chega pelo link do leilão, você recupera a proposta (valores, taxa,
  parcelas) e os dados do cliente (nome, CPF, nascimento, empregador,
  elegibilidade, margem) **antes de pedir qualquer dado na tela** — e
  pré-preenche a jornada. Sem efeitos colaterais: não cria proposta, não
  dispara SMS.

  Requer a Unit no allowlist do seu contrato (`403` sem). Erros com semântica:
  `404` para chave desconhecida/expirada, `502` para falha do banco parceiro.

  **No sandbox**: `sbx-leilao-ok` devolve `200` com um cliente fictício (CPF
  `11144477735`, o mesmo do catálogo — encadeie lookup → consulta →
  formalização com um CPF só); `sbx-leilao-expirada` devolve `404`. A
  collection do Postman ganhou a pasta "Leilão — lookup por proposal\_key".
</Update>

<Update label="30 de julho de 2026" description="Zipdin: causa raiz do erro de 'data de vencimento inicial' resolvida">
  ### Zipdin — submit se recupera sozinho do erro de "data de vencimento inicial"

  Identificamos a causa raiz definitiva do erro
  `initialDueDate: A data de vencimento inicial é obrigatória!` no submit da
  Zipdin: ele ocorre quando a **proposta ainda não tem uma simulação salva**
  do lado do banco — não é um campo do seu request (e o endpoint da Zipdin
  **rejeita** o campo `initialDueDate` se enviado; a derivação automática
  anunciada em 24/07 foi substituída por este mecanismo). Agora, ao receber
  esse erro do banco, a API **salva automaticamente a simulação da oferta
  escolhida e re-tenta o submit** — transparente para a sua integração.

  Nada muda no seu request. Se você envia `initialDueDate` por conta própria,
  pare: o campo é removido do payload antes do envio ao banco.
</Update>

<Update label="29 de julho de 2026" description="Zipdin: chave PIX por e-mail corrigida">
  ### Zipdin — chave PIX do tipo e-mail agora vai com o código correto

  Correção de um defeito de tradução no submit da Zipdin: `recebimento.pix`
  com `tipo_chave: "email"` era enviado ao banco com o código de **telefone**
  (a Zipdin usa `1`=e-mail, `2`=telefone, `3`=CPF, `4`=aleatória). Chaves de
  e-mail podiam ser recusadas ("chave inválida") ou registradas com o tipo
  errado. Se algum submit seu com PIX por e-mail falhou, basta reenviar.
  Os demais tipos (`cpf`, `telefone`→vira chave CPF, `aleatoria`) não mudam.
</Update>

<Update label="27 de julho de 2026" description="Novo banco: Banco PAN (consignado CLT) — sob habilitação">
  ### Banco PAN disponível na API (mediante habilitação no contrato)

  Suporte completo ao **Banco PAN**: consulta, submit, status, formalização e
  sandbox. Como a Crefaz, só aparece pra sua integração quando entrar no
  allowlist do seu contrato.

  Pontos de atenção:

  * **Autorização por WhatsApp**: a consulta devolve o link; o cliente envia
    a mensagem para autorizar. `submit` antes disso volta `422 invalid_input`
    apontando `offer_ref.offer_id` *(corrigido em 14/08 — esta nota dizia
    `provider_unavailable`/retryable, o que nunca foi o comportamento)*; o
    webhook `authorization_result` avisa quando concluir, e a consulta
    seguinte traz as ofertas com `offerId`.
  * `vinculo.matricula` é obrigatória; os termos financeiros são resolvidos
    server-side (o parceiro nunca envia valores).
  * Sandbox: CPFs `400.666.888-09` (fluxo completo) e `500.777.999-76`
    (autorização pendente) — *atualizados em 14/08; os originais tinham
    dígito verificador inválido*.
</Update>

<Update label="27 de julho de 2026" description="Novo banco: Crefaz (Crédito do Trabalhador) — sob habilitação">
  ### Crefaz disponível na API (mediante habilitação no contrato)

  A API de Parceiros ganhou suporte completo à **Crefaz** (Crédito do
  Trabalhador — consignado privado CLT): consulta, submit, formalização,
  status e sandbox. O banco só aparece pra sua integração quando entrar no
  allowlist do seu contrato — fale com o time de parceiros da Unit.

  Pontos de atenção do fluxo Crefaz:

  * **Autorização por SMS (DataPrev)**: a consulta dispara um SMS pro
    cliente; um `submit` antes da autorização volta `422 invalid_input`
    apontando `offer_ref.offer_id` *(corrigido em 14/08 — esta nota dizia
    `provider_unavailable`/retryable, o que nunca foi o comportamento)*. O
    webhook `authorization_result` avisa quando a autorização concluir.
  * **Bloco novo `referencias`**: a Crefaz exige 2 referências pessoais
    (nome + telefone) no dataset de submissão; os demais bancos ignoram.
  * **Recebimento só por conta bancária** (sem PIX), com o código COMPE do
    banco.
  * Sandbox: CPFs `200.444.666-84` (fluxo completo) e `300.555.777-41`
    (SMS pendente) no catálogo de homologação — *o segundo atualizado em
    14/08; o original tinha dígito verificador inválido*.
</Update>

<Update label="24 de julho de 2026" description="Zipdin: data de vencimento inicial enviada automaticamente">
  ### Zipdin não recusa mais submit por "data de vencimento inicial"

  Submits Zipdin feitos um tempo depois da consulta podiam ser recusados com
  "initialDueDate: A data de vencimento inicial é obrigatória!" — o banco
  passa a exigir a data quando o pré-registro não é recente.

  > **Atualização 30/07**: o mecanismo descrito aqui foi substituído — a
  > causa raiz era outra (simulação não salva no banco) e a solução atual
  > está na entrada de 30 de julho. `initialDueDate` não deve ser enviado. Recomendação que continua valendo: formalize o quanto antes
  > após a consulta — ofertas são reprecificadas pelos bancos ao longo do dia.
</Update>

<Update label="23 de julho de 2026" description="Formalização Unit (carteira QI Tech) corrigida + instabilidade do banco sinalizada como retryable">
  ### Formalização Unit em carteira QI Tech não falha mais com 500

  Contratos Unit cuja oferta foi simulada na carteira QI Tech podiam falhar
  na formalização com `provider_error` (500 do banco): o parceiro bancário
  passou a exigir o campo `transfer_method` no bloco de desembolso desse
  caminho. A API agora envia o campo automaticamente — nada muda no seu
  request. Se você recebeu esse erro, basta reenviar o mesmo `submit`.

  ### Instabilidade do banco agora vem como `provider_unavailable` retryable

  Erros crus de infraestrutura do banco (HTTP 5xx) durante o submit
  respondiam `provider_error` com `retryable: false` e HTML no corpo da
  mensagem. Agora respondem **`provider_unavailable` / `retryable: true`**
  (502) com mensagem limpa — seu bot pode re-tentar em alguns minutos com
  segurança (o dedup do lado da API impede duplicidade).

  ### Zipdin traduz estado civil e nacionalidade automaticamente

  No submit da Zipdin, `titular.estado_civil` canônico (ex.: `uniao_estavel`)
  era repassado cru ao banco e recusado ("caracteres não permitidos"), e
  `titular.nacionalidade` textual ou ausente caía em "Favor informar somente
  1 ou 2". A API agora converte os dois para o formato que o banco exige —
  mesma responsabilidade de tradução já exercida nos campos da Facta.
  Continue enviando os valores canônicos da documentação.

  Também na Zipdin: `titular.nome_pai` é opcional, mas o banco recusa o
  submit inteiro se ele vier com nome incompleto (uma palavra só). A API
  agora omite o campo nesse caso em vez de deixar o envio falhar — envie o
  nome completo do pai ou simplesmente não envie o campo.

  ### `offerId` não some mais em consultas longas

  Em consultas muito demoradas (banco lento, >90s), um blip de conexão
  interna podia fazer a resposta chegar com `offerId: null` em todas as
  propostas (e `simulationGroupId: null`) — a persistência das ofertas
  falhava em cascata. A camada de persistência agora é resiliente a esses
  blips e o `offerId` volta a ser garantido em toda resposta com proposta.
  Se você recebeu uma resposta assim, basta re-consultar.
</Update>

<Update label="20 de julho de 2026" description="offerId garantido em toda resposta + classificação de recusas">
  ### `offerId` presente em 100% das consultas

  Re-consultas em sequência rápida (menos de 60s) podiam voltar com
  `offerId: null`, forçando o uso do `simulationId` — que na Unit muda a
  cada chamada e não era reconhecido no submit. Agora **toda** resposta da
  consulta agregada traz `offerId`: a mesma oferta mantém o **mesmo id**
  entre consultas (estável), e ofertas novas ganham id próprio. O caveat dos
  60s deixa de existir. Use sempre o `offerId` no `offer_ref.offer_id`.

  ### Recusa por estado do cliente não é "banco indisponível"

  Recusas determinísticas como "Cliente possui contrato em andamento" agora
  respondem **`provider_rejected` / `retryable: false`** (422) com a
  mensagem real do banco — antes saíam como `provider_unavailable`
  retryable (502), induzindo retry em loop. Nesses casos, ofereça outro
  banco ao cliente em vez de repetir o envio.

  ### Um card por jornada + fases fiéis no acompanhamento

  Consultas repetidas do mesmo CPF passaram a reutilizar a mesma proposta
  interna (o `proposal_id` do submit fica estável entre consultas), e o
  andamento reflete a fase real (em simulação / sem oferta disponível).
</Update>

<Update label="17 de julho de 2026" description="Facta: tradução de cidade/nacionalidade + classificação correta de validação">
  ### Facta traduz cidade e nacionalidade automaticamente

  No submit da Facta, `endereco.cidade` e `titular.naturalidade_cidade`
  agora são convertidos automaticamente do nome do município para o código
  que o banco exige, e `titular.nacionalidade` textual ("Brasileira") vira o
  código do banco — mesma responsabilidade de tradução que a API já exerce
  para `estado_civil` e `tipo_conta`. Continue enviando os valores humanos
  canônicos.

  ### Erro de validação não aparece mais como "banco indisponível"

  Rejeições determinísticas de campo pelo banco agora respondem
  **`provider_rejected` com `retryable: false`** (HTTP 422) — antes saíam
  como `provider_unavailable`/`retryable: true` (502), o que induzia bots a
  reapresentar o mesmo request em loop. Se receber `provider_rejected`,
  corrija os dados; `provider_unavailable` segue reservado para
  indisponibilidade real (aí sim, retry).
</Update>

<Update label="16 de julho de 2026" description="Formalização corrigida nos 4 bancos + status honesto">
  ### Submit Unit — contrato idêntico ao fluxo interno

  O `submit` de propostas Unit podia falhar com `provider_error` (500 do
  banco): o contrato enviado divergia do formato que o fluxo interno usa em
  produção (taxa em formato errado, vencimento ausente, identificadores
  trocados e carteira diferente da simulação). Agora o contrato é montado
  integralmente a partir da oferta persistida na consulta e sai **na mesma
  carteira em que a oferta foi simulada**. Nada muda no seu request — mesmo
  `offer_ref.offer_id` de sempre.

  ### Formalização C6 e Facta corrigidas + desembolso Unit

  Auditoria completa de paridade contra o fluxo interno de produção:

  * **C6**: o identificador de simulação passou a ser resolvido server-side a
    partir do `offer_ref.offer_id` da consulta (numérico `offerId` ou o
    `id_simulacao` nativo — ambos aceitos); tipo de conta agora aceita
    formatos comuns ("corrente", "poupança", códigos) e é traduzido pro enum
    do banco; dígitos de agência/conta são normalizados.
  * **Facta**: conta de recebimento montada com o dígito verificador; estado
    civil aceita a palavra em português ("solteiro", "casado"...) além do
    código; o link de formalização agora fica disponível também no
    `formalize` e no status (antes só na resposta do submit).
  * **Unit**: dados de desembolso (PIX/conta) corrigidos para o formato do
    banco — chave PIX de CPF/celular é normalizada automaticamente; contrato,
    assinatura e status operam sempre na mesma carteira da oferta.

  Nada muda na forma de chamar a API — mesmos campos, mais robustez.

  ### Zipdin: submit e formalização corrigidos

  A formalização Zipdin via API não funcionava: identificadores internos
  vazavam para o banco, a conveniada ia vazia e datas em formato ISO eram
  rejeitadas. Corrigido de ponta a ponta: a proposta do pré-registro é
  resolvida server-side a partir do `offer_ref.offer_id` da consulta, a
  conveniada é preenchida automaticamente, datas são convertidas ao formato
  do banco e chave PIX de telefone é substituída pela chave CPF do titular
  (a Zipdin não aceita PIX por telefone). Mesmo request de sempre — refaça a
  consulta antes do submit para garantir uma oferta atualizada.

  ### Status mais honesto no acompanhamento de propostas

  * `GET /proposals/{id}` agora retorna **`awaiting_signature`** enquanto o
    contrato aguarda a assinatura do titular (Unit e Facta) — antes o status
    podia aparecer como `created` ou até `disbursed` nessa fase.
  * Consulta agregada com tempo-limite explícito: sob lentidão extrema de um
    banco, a resposta é `502 provider_unavailable` (retryable) no formato do
    contrato — não mais um 504 genérico do proxy.
  * Consultas simultâneas do mesmo CPF por integrações diferentes não se
    misturam mais (cada parceria mantém sua própria proposta).
  * `cancel`: suportado apenas pela Facta (agora refletido corretamente —
    demais bancos retornam `501`).
</Update>

<Update label="15 de julho de 2026" description="offerId universal, modos de simulação, fallback de carteira e GET /banks">
  ### `offerId` em toda oferta + formalização Facta funcional

  A consulta agregada agora retorna **`offerId`** em cada oferta — o
  identificador canônico para o `offer_ref.offer_id` do submit, em qualquer
  banco.

  * **Facta:** a formalização passou a resolver a oferta **server-side** — a
    API re-executa a simulação no momento do submit com os dados da tabela
    escolhida. O identificador **nunca expira**; se a tabela não estiver mais
    elegível, a resposta é `409 offer_expired` (refaça a consulta).
    Corrige o contrato anterior, que pedia um `id_simulador` que a consulta
    de produção não retornava.
  * **Unit:** também aceita o `offerId` (o `simulationId` legado continua
    válido).
  * **C6/Zipdin:** na época, seguiam com os ids nativos do `providerData` —
    desde 16/07 o `offerId` também é resolvido server-side para os dois.
  * `offerId` pode vir `null` apenas ao repetir a **mesma** consulta sem
    parâmetros em menos de 60 segundos (dedup de re-clique) — aguarde e
    re-consulte. Re-simulações com valor/parcela/prazo sempre trazem
    `offerId` (ver abaixo).

  ### `offerId` imediato na re-simulação com parâmetros

  O fluxo natural — consultar, ver a oferta máxima, o cliente pedir outro
  valor e re-consultar em seguida — caía na janela de deduplicação de 60
  segundos e as ofertas novas voltavam com `offerId: null`, impedindo o
  submit imediato. Agora toda consulta com `loan_value`, `valor_parcela` ou
  `prazo` persiste as ofertas na hora: a resposta traz `offerId` utilizável
  no ato, sem espera. A janela de 60s continua valendo só para a repetição
  da **mesma** consulta sem parâmetros (proteção contra duplo clique).

  ### Simulação por valor sem prazo agora funciona na Unit

  `loan_value` enviado **sem** `prazo` passava batido na Unit: o valor pedido
  era ignorado e a resposta trazia a proposta máxima disponível. Agora a Unit
  assume **48 parcelas** (o mesmo default do nosso formulário interno) e
  ajusta automaticamente quando o prazo não está disponível — o valor pedido
  é honrado. Para fixar um prazo específico, envie `prazo` junto. Os dois
  modos de simulação ("por valor final" e "por parcela") estão documentados
  nos campos da consulta.

  ### Unit consulta duas carteiras antes de responder "sem proposta"

  A elegibilidade na Unit é por carteira: um cliente inelegível na carteira
  padrão (BMP) pode ter oferta na QI Tech — e a consulta parava na primeira,
  devolvendo "sem proposta" para clientes com crédito disponível. Agora, se
  nenhum vínculo for elegível na carteira padrão, a consulta tenta
  automaticamente a QI Tech antes de responder. Nada muda no seu contrato de
  integração: mesma chamada, mesma resposta — apenas mais ofertas. A
  formalização usa automaticamente a mesma carteira da oferta.

  ### Formalização Unit devolve o link de assinatura de forma confiável

  Contratos Unit emitidos pela carteira BMP já nascem com o link de assinatura
  (QiSign), mas uma falha na captura do identificador da CCB fazia o
  `formalize` responder erro em vez do link em alguns cenários — inclusive ao
  reformalizar um contrato já existente. Corrigido: o identificador e o link
  são persistidos na emissão e o `formalize` devolve o link direto
  (`requires_action` + `signatureUrl`), sem depender de nova chamada ao banco.

  ### Lista de bancos para conta de recebimento

  Novo endpoint [`GET /partners/v1/banks`](/#lista-de-bancos): devolve os
  códigos COMPE aceitos em `recebimento.conta_bancaria.banco` —
  `{"banks": [{"code", "name"}]}`. Use para popular o seletor de banco no seu
  formulário; a aceitação final por instituição segue validada no submit.
</Update>

<Update label="14 de julho de 2026" description="Webhook de autorização do C6 + validação na borda">
  ### Webhook de autorização do C6 (biometria)

  O evento [`authorization_result`](/#webhooks) do **C6** entrou no ar. Quando o
  titular conclui a prova de vida, a Unit envia um webhook com as ofertas do C6
  já embutidas — você não precisa mais ficar consultando o status para saber que
  a autorização foi concluída.

  * **Payload com ofertas.** O webhook traz `event: "authorization_result"`,
    `status: "approved"` e o array `offers` no mesmo formato da consulta síncrona.
  * **Assinado.** Header `X-Unit-Signature` (HMAC-SHA256 do corpo). Valide sempre
    com comparação em tempo constante.
  * **Entrega at-least-once.** Trate os webhooks de forma idempotente,
    deduplicando por `(external_reference, event)`.

  A documentação do **modelo de autorização do C6** foi esclarecida: a biometria
  acontece **antes** da oferta — a consulta retorna o link de biometria e as
  ofertas do C6 chegam depois (por webhook ou numa nova consulta do mesmo CPF).

  <Info>
    **Sandbox:** o CPF de teste `12345678909` simula esse fluxo de ponta a ponta —
    a 1ª consulta retorna `requires_action` + link e, \~15s depois, as ofertas são
    liberadas e o webhook dispara. Configure um `webhook_url` no cadastro sandbox
    para recebê-lo.
  </Info>

  ### Validação mais clara na entrada

  * **`telefone`**: formato canônico é **DDD+número (10-11 dígitos)**; o DDI
    `55` é aceito e removido automaticamente. Fora disso, `422 invalid_input`.
  * **`email`**: obrigatório em formato válido (o HubCrédito não processa
    consultas sem e-mail).
  * **Erros de validação** nas rotas `/partners/v1/*` agora respondem
    `422` com o envelope documentado
    (`{"code": "invalid_input", "message", "retryable", "field"}`) — antes
    saíam como `400` num formato interno.
</Update>

<Update label="6 de julho de 2026" description="Lançamento público da API de Parceiros">
  ### Lançamento público da API de Parceiros

  Primeira versão pública da API `/partners/v1/*`, cobrindo o fluxo completo de
  originação de crédito consignado em múltiplos bancos numa integração única.

  * **Consulta agregada multi-banco.** `POST /partners/v1/consultas` — numa
    chamada você consulta todos os bancos habilitados para a sua parceria (ou um
    subconjunto), com resposta síncrona ou por streaming (SSE).
  * **Formalização unificada.** `submit`, `formalize`, `status` e `cancel` num
    contrato único para **Zipdin, Unit, C6 e Facta** — link de assinatura e
    acompanhamento de status inclusos.
  * **Sandbox de homologação.** Ambiente 100% simulado (`sandbox.api.somosunit.com.br`),
    com catálogo de CPFs de teste para cada cenário — sem tocar em nenhum banco real.
  * **Collection do Postman.** Endpoints e environments (produção e sandbox)
    prontos para importar.
</Update>
