A consulta/cotação e a formalização desta API estão implementadas e
disponíveis: as rotas
/partners/v1/* — incluindo a submissão de dados
complementares, o link de assinatura e o acompanhamento de status descritos em
Formalizando uma proposta — já estão no ar. O
ato de assinar continua acontecendo no fluxo regulado do próprio banco
(ZipSign, biometria, DATAPREV); a API entrega o link para o cliente completar.
Para obter credenciais (API key e configuração de webhook), fale com o time de
parceiros da Unit.Visão geral
Sua aplicação já coleta os dados do cliente e o consentimento dele. Em vez de integrar banco a banco, você faz uma única chamada para a Unit com os dados do titular e a evidência de autorização — a Unit decide, banco a banco, como rotear: Você recebe, numa resposta só, o resultado de cada banco: as ofertas dos que aceitaram a evidência direto, e as ações pendentes (link de biometria, DATAPREV, etc.) dos que exigem uma autorização externa do titular — mais o erro ou o motivo, por banco, quando não houver oferta.Como isso se encaixa no seu fluxo
Você não precisa mudar a experiência do seu produto — a API de Parceiros entra depois que você já tem os dados e o consentimento do cliente:1
Colete os dados do titular
CPF, nome completo, data de nascimento, telefone e e-mail — o que você já
coleta hoje no seu onboarding.
2
Colete o consentimento e a evidência
Apresente o termo de autorização para consulta de margem/vínculo no seu
produto e registre a evidência do aceite: IP do titular, geolocalização e o
momento do aceite.
3
Chame a API de Parceiros
Envie os dados e a evidência para uma das rotas de consulta (abaixo). Numa
chamada só você consulta todos os bancos habilitados para a sua parceria —
ou um subconjunto, ou um banco específico.
4
Trate a resposta
Mostre as ofertas retornadas. Para bancos que exigem autorização externa,
apresente o link de ação para o cliente completar (ex.: biometria).
5
Receba atualizações assíncronas (quando aplicável)
Bancos assíncronos, ou autorizações externas concluídas depois da resposta
inicial, chegam via webhook — não é preciso ficar consultando
o status.
Autenticação
Toda chamada usa uma API key exclusiva do seu parceiro, enviada no header:401.
Bancos habilitados
Quais bancos a sua integração pode consultar é definido em duas camadas:- Allowlist da parceria (fixo, no servidor). Cada parceria tem uma lista de bancos permitidos, definida no seu contrato. A Unit aplica esse limite sempre — uma chamada nunca alcança um banco fora do seu allowlist.
- Seleção por chamada (opcional, dentro do allowlist). Em cada requisição
você pode restringir ainda mais quais bancos consultar, com o campo
providers(veja abaixo). Ausente, a consulta usa todo o seu allowlist.
A cobertura de bancos disponível para a sua integração depende do seu
contrato de parceria — confirme com o time de parceiros da Unit quais bancos
estão habilitados para você.
Enviando uma consulta
Há três formas de consultar, todas com o mesmo corpo de requisição:Corpo da requisição
string
required
CPF do titular, apenas dígitos.
string
required
Nome completo do titular.
string
required
Data de nascimento no formato
YYYY-MM-DD.string
required
Telefone do titular no formato DDD+número, 10-11 dígitos (ex.:
11999998888). O DDI 55 é opcional — se vier (5511999998888), a API
remove automaticamente. Qualquer outro formato retorna 422 invalid_input.string
required
E-mail do titular, em formato válido. Vazio ou inválido retorna
422 invalid_input — o HubCrédito não processa consultas sem e-mail.string
required
IP do titular no momento do aceite — parte da evidência de autorização.
Como sua chamada é feita pelo seu backend, este campo precisa vir explícito: a
Unit não tem como inferir o IP do seu cliente a partir da sua infraestrutura.
object
Geolocalização do titular no momento do aceite —
{ "lat": number, "lng": number }.
Recomendado; alguns bancos usam esse dado como parte da evidência.string[]
Restringe esta chamada a um subconjunto dos bancos (ex.:
["unit", "c6"]). O
resultado é sempre a interseção com o allowlist da sua parceria — pedir um
banco fora do allowlist não o inclui. Ausente, consulta todo o allowlist.
(Ignorado na rota individual, que já mira um banco pelo path.)Desde 13/08: se nenhum nome pedido estiver no seu allowlist (ex.: typo
"pan" em vez de "banco_pan"), a chamada devolve 422 invalid_input
(field: "providers") listando os bancos disponíveis do seu contrato — em
vez de responder 200 com providerResults vazio.integer
default:"0"
Sexo do titular, quando exigido por algum banco na simulação.
object
Bloco opcional para elevar a força da evidência em bancos que aceitam
autorização “tipo app”:
authorizationId, signatureDate e um objeto
evidence com userAgent, operationalSystem, deviceModel, deviceName,
deviceType e geoLocation. Use se você já capturar esses dados de device na
sua própria integração.string
Identificador de originação/atribuição, quando aplicável ao seu contrato.
Na maioria dos casos, não envie: a consulta usa a carteira padrão de cada
banco (na Unit, com fallback automático de carteira quando não há vínculo
elegível).
number
Modo “por valor final”: simula o valor de empréstimo desejado. Envie
junto com
prazo; se prazo for omitido, a Unit assume 48 parcelas
(o mesmo default do nosso formulário) e ajusta automaticamente quando o
prazo não está disponível para o cliente. Opcional.integer
Número de parcelas desejado. Acompanha
loan_value (por valor) ou
valor_parcela (por parcela). Opcional — default 48 no modo por valor.number
Modo “por parcela”: simula pela parcela mensal desejada — o valor é
derivado automaticamente. É o modo universal (todos os bancos simulam por
parcela). Envie junto com
prazo. Opcional. Quando loan_value e
valor_parcela vêm juntos, o valor tem prioridade.boolean
default:"true"
Inclui as opções com seguro na simulação.
Resposta — consulta agregada
A rota agregada devolve, numa resposta só, as ofertas achatadas (ordenadas por valor) e o resultado detalhado por banco:array
Todas as ofertas de todos os bancos, achatadas e ordenadas por valor. Cada
oferta traz
provider, loanValue, installmentValue, installments,
interestRate, totalAmount e detalhes do vínculo (employerName,
employerCnpj, matricula), além de providerData com campos específicos do
banco.Cada oferta também traz adjusted (bool) e adjustments (array de
strings legíveis): quando os parâmetros pedidos (prazo, loan_value,
valor_parcela) não puderam ser atendidos exatamente, a oferta volta com o
melhor possível e o ajuste sinalizado — ex. "prazo solicitado (36x) indisponível — melhor prazo: 18x" ou "valor solicitado acima do máximo disponível". Use-os para não apresentar a simulação como se fosse
exatamente a pedida.object
Resultado detalhado por banco, indexado pelo nome do banco. É onde você lê
o estado de cada um:
- Ofertas do banco →
proposals. - Ação pendente (autorização externa) →
requiresSignature: truecomsignatureUrl, e/ounoProposalReasonsexplicando o que falta. - Erro / recusa →
success: falsecomerror.
array
Empregadores únicos (por CNPJ) encontrados para o titular:
{cnpj, name, matricula, provider, margin}. margin é a margem consignável
disponível, apurada em tempo real na consulta, normalizada em número
(float) a partir do que o banco do vínculo informa (Unit e Facta trazem
hoje); vem null quando o banco não informa margem. Não confundir com o
consigned_credit_balance do lookup de leilão, que é o retrato no momento
em que o convite do leilão foi gerado.integer
Tempo total da consulta agregada, em milissegundos.
string | null
Identificador do grupo de simulação, quando a consulta persiste as ofertas.
Resposta — streaming (SSE)
A rota/consultas/stream responde text/event-stream: cada evento é uma linha
data: {json}\n\n com uma chave event. Os bancos chegam à medida que
respondem, sem esperar o mais lento:
O streaming entrega os resultados progressivos por banco, mas não dispara
os efeitos cross-provider da rota síncrona (webhooks de lead, persistência das
ofertas). Se você depende desses efeitos, use a rota agregada síncrona
(
POST /partners/v1/consultas).Resposta — consulta individual
A rota individual devolve um único envelope do banco consultado (campos emsnake_case):
string
Estado normalizado do banco:
ok (com oferta), no_offers (sem oferta),
requires_action (precisa de autorização externa), pending (fluxo
assíncrono em andamento) ou error.array
Ofertas deste banco.
object | null
Ação pendente quando
status: requires_action — type
(signature | biometria | dataprev | whatsapp_link | formalization),
url (o link para o cliente completar) e detail.string | null
Motivo, quando o banco falhou ou recusou.
Pedir um banco fora do seu allowlist retorna
403 (não 404 — a API não
revela se o banco existe). Um nome de banco desconhecido retorna 404.Fluxo de leilão — lookup por proposal_key
Quando o cliente chega até você pelo fluxo de leilão (link com
?proposal_key=... na URL), você pode recuperar a proposta do leilão e os
dados do cliente antes de pedir qualquer coisa na tela — e pré-preencher a
jornada inteira:
200):
disbursed_issue_amountna raiz = valor pedido pelo trabalhador no leilão da CTPS.proposal.proposal_data.disbursed_issue_amount= valor da proposta enviada (o lance real). Apresente ao cliente sempre o deproposal_data, usandoproposal_data.simulationpara parcela/CET; o da raiz serve para contexto (“você pediu X, conseguimos Y”).consigned_credit_balance= margem disponível no momento em que o convite do leilão foi gerado — pode estar defasada. A margem em tempo real é aemployers[].marginda consulta. Para régua de elegibilidade, use este campo como pré-filtro barato e a margem da consulta como critério final.- Campos de repasse (
webhook_type,alerts,rank_position,event_datetime,inclusion_limit_datetime,external_proposal_urle as chaves internas*_key): vêm da instituição como estão, podem virnull(orank_positioninclusive em produção) e podem mudar sem aviso — não construa lógica obrigatória sobre eles. O que tem prazo é o lance (expiration_datetime); a chave em si continua resolvendo depois disso.
A
proposal_key é uma capability: opaca, não-enumerável, e chega até
você pelo próprio link do leilão. A expiração do convite do leilão não
invalida a chave — dias depois ela ainda resolve, o que permite retomar uma
jornada abandonada.No sandbox, use as chaves de teste
sbx-leilao-ok (retorna 200 com um
cliente fictício — CPF 11144477735, o mesmo do catálogo de cenários, então
você encadeia lookup → consulta → formalização com um CPF só) e
sbx-leilao-expirada (retorna 404, para testar seu tratamento de erro).Modelo de autorização por banco
Nem todos os bancos aceitam a evidência da mesma forma. Alguns autorizam a consulta direto com os dados enviados na chamada; outros exigem uma ação externa do titular:C6 — a biometria vem antes da oferta. Diferente dos outros bancos, o C6 só
gera oferta depois que o titular conclui a prova de vida. Enquanto isso, a
consulta retorna o C6 sem oferta, com o link de biometria em
action (type: "biometria"). Quando o cliente conclui:- a Unit envia o webhook
authorization_resultcom as ofertas do C6; e - as ofertas também passam a aparecer numa nova consulta do mesmo CPF (fallback caso você não use webhook).
GET /partners/v1/proposals/{id} não
se aplica nessa espera — ainda não existe proposta (o submit vem depois da oferta).Autorização com colheita de evidência (fluxo WhatsApp)
Atendimentos 100% WhatsApp não têm como colher a evidência de autorização que Zipdin, Unit e Facta exigem (IP do titular, geolocalização, dispositivo). Para esses casos, a API gera um link de autorização: o cliente abre uma página compacta, lê o termo LGPD e autoriza com um toque — a evidência é colhida ali (IP real capturado no servidor, geolocalização, dispositivo, versão do termo) e fica registrada na Unit como fonte da verdade.1
Crie a sessão
POST /partners/v1/authorizations com {cpf, nome, telefone} →
{authorization_id, url, expires_at} (validade 72h). Idempotente: sessão
pendente viva do mesmo CPF devolve o mesmo link.2
Envie o link na conversa
O cliente abre a
url, vê o termo com o nome dele e CPF mascarado, e
autoriza com um toque. Localização negada não bloqueia (fica registrada
como não-colhida).3
Receba o sinal
Webhook
authorization.completed no seu webhook_url (mesma assinatura
HMAC do authorization_result) — ou poll em
GET /partners/v1/authorizations/{authorization_id}, que devolve o
status e, quando autorizada, a evidence completa:4
Consulte com o authorization_id
Nas rotas de consulta, envie
authorization_id no lugar de
client_ip: a evidência colhida é injetada no servidor — sua integração
nunca transita IP/geo do cliente.No sandbox o fluxo inteiro é testável por API: as rotas
public/* são
abertas, então o passo do cliente pode ser simulado chamando
POST /partners/v1/authorizations/public/{authorization_id}/accept
diretamente com uma evidência de teste. A collection do Postman tem a pasta
“Autorização — colheita de evidência” com os 5 passos prontos.Formalizando uma proposta
Depois que o cliente escolhe uma oferta, a operação ainda precisa ser formalizada com o banco — e isso exige um segundo conjunto de dados, que a consulta de evidência (acima) não cobre: endereço completo, dados bancários ou chave PIX para o desembolso, documento de identidade, estado civil e dados de emprego e renda. A API de Parceiros cobre também essa etapa — submissão dos dados complementares, link de assinatura e acompanhamento de status — nas mesmas rotas/partners/v1/proposals*.
1
Escolha uma oferta
Use o
provider e o identificador da oferta retornados na consulta (ver
offer_ref abaixo).2
Submeta os dados complementares
POST /proposals com a oferta escolhida (offer_ref) e o dataset de
submissão (endereço, documento, dados bancários/PIX etc.). A resposta traz
o proposal_id — nosso identificador estável para o restante do fluxo.3
Peça o link de assinatura
POST /proposals/{proposal_id}/formalize devolve action.url: o link
para o cliente completar a assinatura no fluxo do banco (ZipSign,
biometria, DATAPREV etc.).4
Acompanhe o status
GET /proposals/{proposal_id} devolve o status normalizado a qualquer
momento, sem que você precise reimplementar o fluxo de cada banco.Rotas
O ato de assinar acontece no fluxo regulado do banco (ZipSign, biometria C6,
DATAPREV, Unit-sign) — a API de Parceiros entrega o link e o status; ela não
captura a assinatura.
Dataset de submissão
POST /proposals recebe um objeto único, o mesmo para todos os bancos. A
API valida o subconjunto exigido pelo banco-alvo e devolve 422 com o(s)
campo(s) faltando, antes de qualquer chamada ao banco.
object
required
A oferta escolhida —
{ provider, offer_id }. Envie o offerId que veio
em cada oferta da consulta — ele identifica a oferta persistida e é
resolvido server-side para os quatro bancos: a API recupera os
identificadores e termos reais da oferta (na Facta, a simulação é
re-executada no momento do submit — o identificador nunca expira; na
Zipdin, a proposta do pré-registro é localizada automaticamente). Compat:
os identificadores nativos do providerData continuam aceitos.object
required
Dados do titular:
nome, cpf, data_nascimento, sexo ("M" ou "F" —
normalizado; a API traduz para o código de cada banco), nome_mae, e,
conforme o banco, nome_pai, nacionalidade, estado_civil,
naturalidade_cidade, naturalidade_uf, exposicao_politica.
nacionalidade e naturalidade_cidade vão por extenso (“Brasileira”,
“São Paulo”) — a API traduz para o código exigido por cada banco.
estado_civil: envie a palavra em português — solteiro, casado,
divorciado, viuvo, separado ou uniao_estavel; a API traduz para o
código/formato de cada banco (não envie códigos numéricos — a numeração
varia por banco).object
Documento de identidade (RG):
numero, orgao_emissor, uf_emissor,
data_emissao. Exigido pela maioria dos bancos — ver matriz abaixo.object
required
telefone e email do titular.object
required
Endereço completo:
cep, logradouro, numero, complemento (opcional),
bairro, cidade, uf.object
Dados de emprego e renda:
cnpj_empregador, nome_empregador, cargo,
salario, margem, data_admissao, matricula. Exigência varia por
banco — ver matriz abaixo.object
required
Para onde o crédito é desembolsado — exatamente um dos dois:
conta_bancaria (banco, agencia, digito_agencia opcional, conta,
digito_conta, tipo_conta) ou pix (tipo_chave, chave). Enviar os
dois, ou nenhum, retorna 422. O campo banco usa o código COMPE —
consulte a lista aceita em GET /partners/v1/banks.tipo_conta:corrente,poupancaousalario(a API traduz para o enum de cada banco). Máscaras em agência/conta/CEP são removidas automaticamente.pix.tipo_chave:cpf,telefone,emailoualeatoria. Chave de CPF/celular é normalizada para o formato do banco. Zipdin não aceita PIX por telefone — nesse caso o desembolso vai para a chave PIX-CPF do titular.
object
required
ip — IP do titular no momento do aceite. tipo_envio ("sms" ou
"whatsapp") controla como o link de assinatura é entregue, quando o banco
suportar.Matriz de exigência por banco
Cada bloco é obrigatório, opcional ou irrelevante conforme o banco. Campos faltando para o banco-alvo retornam422 com o campo, antes de qualquer
chamada externa.
¹ Na Unit, PIX é bloqueado para propostas roteadas para a carteira BMP — a
validação recusa
pix nesse caso, com mensagem clara.
² Na Zipdin, vinculo cobre apenas cargo/empregador — não inclui renda.
³ A Crefaz exige 2 referências pessoais (nome + telefone; grau:
0=cônjuge, 1=parente, 2=amigo — default parente). Envie no bloco
referencias do dataset (os demais bancos ignoram o bloco).
Banco PAN — fluxo assíncrono (autorização por WhatsApp). A consulta
devolve uma ação pendente com o link de WhatsApp do banco — o cliente
precisa enviar a mensagem para autorizar. Enquanto isso, um
submit
retorna 422 invalid_input apontando offer_ref.offer_id (ainda não
existe oferta precificada para submeter — não é um erro retryable de
infraestrutura). Concluída a autorização (o webhook authorization_result
avisa), a próxima consulta devolve as ofertas precificadas com offerId —
daí em diante o fluxo é o padrão (submit → status → formalize com link
digital).Crefaz — fluxo assíncrono (autorização por SMS). A consulta dispara um
SMS DataPrev pro cliente; enquanto ele não autorizar, a consulta volta com
ação pendente e um
submit retorna 422 invalid_input apontando
offer_ref.offer_id — aguarde o webhook authorization_result (ou
re-consulte) e submeta com o offerId novo. Depois da Mesa aprovar, o
formalize entrega o link de assinatura (Unico) e o status reporta
awaiting_signature.Envelope de resposta
submit, formalize e status devolvem o mesmo envelope — você escreve
um handler de status e um de erro, independente do banco:
string
Nosso identificador opaco e estável da proposta — use-o em
formalize,
status e cancel.string
Estado normalizado da proposta (enum abaixo).
object | null
Link de assinatura quando
status: awaiting_signature — type: "signature",
url (o link para o cliente completar) e delivery.object | null
A oferta associada à proposta (
loanValue, installmentValue,
installments, interestRate, …).object | null
Erro normalizado, quando houver —
code, message, retryable e field
(ver tabela de códigos abaixo).object | null
Extensão crua por banco: identificadores e status originais, para quem
precisar do detalhe.
Status normalizado
Códigos de erro
O contrato de erro é normalizado — um handler para o parceiro, não um por banco.error.code é estável entre bancos; retryable indica se vale a pena
tentar de novo; field aponta o campo, quando aplicável.
Segurança
Exemplo
formalize, com o link de assinatura pronto:
Lista de bancos
GET /partners/v1/banks (autenticado pela mesma API key) devolve as
instituições bancárias aceitas em recebimento.conta_bancaria.banco:
Sandbox de Homologação
Antes de integrar em produção, teste sua integração no sandbox — um ambiente que responde exatamente como a API real (mesmas rotas, mesmo contrato, mesmos códigos de erro), mas 100% simulado: não bate em nenhum banco de verdade e não usa dados reais.Base URL do sandbox:
https://sandbox.api.somosunit.com.br. Chave de teste
fixa (pública, pode usar livremente): au_sandbox00000000000000000000000.CPFs de teste — catálogo de cenários
Re-simulação no sandbox (14/08):
prazo, loan_value e
valor_parcela 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 do teto volta clampado, com o ajuste sinalizado em
adjusted/adjustments. Os números seguem um modelo linear simplificado
(sem juros compostos) — use para homologar o fluxo de re-simulação e teto,
não para validar precificação.GET /auction-proposals/{key}): sbx-leilao-ok → 200 e
sbx-leilao-expirada → 404 — ver Fluxo de leilão.
Use
POST /partners/v1/consultas (agregada) antes do submit — não a rota
individual. Só a agregada persiste as ofertas e devolve o offerId que
o submit usa (offer_ref.offer_id), igual em produção. O offerId vem
preenchido em todas as respostas da consulta agregada — inclusive em
re-consultas imediatas (a mesma oferta mantém o mesmo offerId entre
consultas; ofertas novas ganham id próprio). Use sempre o offerId — o
simulationId do providerData muda a cada consulta na Unit.Collection do Postman
Baixe a collection com todos os endpoints (consulta e formalização) e os dois environments prontos (produção e sandbox): Importe os 3 arquivos no Postman, selecione o environment desejado e preenchaapiKey (produção) — no sandbox a chave já vem preenchida.
Webhooks
Para bancos assíncronos e para autorizações externas que se completam depois da resposta inicial (ex.: C6 após a biometria), a Unit notifica sua aplicação via webhook, na URL configurada no cadastro do seu parceiro.A configuração de webhook (URL + secret) já faz parte do cadastro do parceiro.
O evento
authorization_result do C6 (pós-biometria) já está no ar:
quando o cliente conclui a prova de vida, a Unit envia o webhook com as ofertas
do C6. O Banco PAN segue a mesma forma quando entrar no fluxo automatizado.Payload
Verificando a assinatura
Toda chamada de webhook inclui um headerX-Unit-Signature com um HMAC-SHA256
do corpo da requisição, assinado com o webhook secret do seu cadastro. Valide a
assinatura antes de processar o payload:
2xx para confirmar o recebimento. Chamadas sem
confirmação são reenviadas com backoff.
A entrega é at-least-once: em cenários raros (uma falha de rede entre a
gravação da oferta e o envio), o mesmo evento pode chegar mais de uma vez.
Trate os webhooks de forma idempotente — deduplique pela combinação
(external_reference, event).
