Antecipação de saque-aniversário do FGTS, ponta a ponta: abrir a solicitação, receber as ofertas
das bancarizadoras, submeter o KYC e contratar.Todos os endpoints deste grupo exigem o scope proposals:write na sua api-key — inclusive os GET
de acompanhamento, porque quem origina precisa acompanhar o que originou. Sem ele a resposta é
403, mesmo com um token válido. proposals:write é distinto de proposals:read, que dá acesso à
listagem de propostas já contratadas em /api/v1/proposals.O fluxo em cinco passos#
1. POST /applications → 202, status QUOTING
2. GET /applications/{id}/status ↻ até sair de QUOTING
3. POST /applications/{id}/kyc → cadastro completo do cliente
4. POST /applications/{id}/offers/{offer_id}/accept → 202, contratação iniciada
5. GET /applications/{id}/status ↻ até DISBURSED (ou terminal de recusa)
Os estados e para onde eles vão#
O caminho central é o de sucesso; as saídas laterais são os desfechos que você precisa tratar.ENDORSED aparece destacado porque é a fronteira sem volta: até ali dá para cancelar e tentar
outro caminho; a partir dali o CPF está averbado naquele banco.Três leituras que o desenho torna óbvias:CONTRACT_REJECTED não encerra nada. É o único estado de falha do qual se volta — aceitando
outra oferta do mesmo menu.
ENDORSED é a fronteira sem volta. Antes dela, cancelar e tentar outro caminho é viável;
depois, o CPF está averbado naquele banco.
Só QUOTING e CONTRACTING são estados de espera. Nos demais, ou você age, ou acabou.
1. Abrir a solicitação. Só o CPF é necessário.#
No FGTS quem determina o valor é o saldo do cliente, não um valor pedido — por isso não existe campo de valor solicitado. A resposta vem em
QUOTING, com offers vazio: a cotação nas bancarizadoras roda em paralelo, em background.Informe também o user_uuid do operador que conduz a venda, para que a proposta e a comissão fiquem
com ele. O campo passa a ser obrigatório em 05/10/2026 — ver
Vincular a operação ao seu operador.2. Aguardar as ofertas.#
Faça polling em GET /applications/{id}/status, que é o endpoint
enxuto (sem quotes/offers no corpo). Quando status virar OFFERS_AVAILABLE, busque o GET
completo para ler o menu.O offers[] vem ordenado por net_amount crescente, com as bancarizadoras misturadas — no
FGTS a comissão é inversa ao valor liberado, então a oferta que abre o menu é a de maior comissão.
Empate no líquido é desempatado pelo offer_id, só para a ordem ser estável entre chamadas; ofertas
recusadas (sem líquido) ficam no fim.Cada oferta traz a tabela que a originou em dois campos: table_name, o rótulo que o cliente lê, e
table_id, o uuid dela no cadastro da plataforma — o mesmo que aparece no table_identifier da
proposta depois do aceite. Para conciliar ou aplicar política própria por tabela, use o
table_id: o nome é rótulo comercial e muda quando a bancarizadora renomeia a tabela, o uuid não.
Ausente quando a bancarizadora não devolveu a tabela da condição — aí a oferta fica sem tabela
identificada, o que não é erro.Atenção ao quotes_pending: OFFERS_AVAILABLE com quotes_pending > 0 significa "já dá para
agir, mas mais ofertas ainda podem chegar". Você escolhe entre apresentar o que já tem ou esperar
o menu fechar — a plataforma fecha a janela sozinha por deadline. Se ninguém ofertar, o estado vira
NO_OFFERS e a solicitação termina ali.3. Submeter o KYC.#
O cadastro completo é obrigatório antes do aceite — aceitar sem KYC responde 409 KYC_REQUIRED. Chame primeiro o GET /applications/{id}/kyc: ele volta
pré-preenchido com o que a plataforma já conhece daquele CPF, o que poupa redigitação. Confirme ou
substitua os valores e submeta no POST.O POST /kyc é upsert e não exige Idempotency-Key — de propósito, para que corrigir um dado
errado seja só reenviar.4. Aceitar uma oferta.#
Escolha um offer_id do menu e aceite. O aceite é único por solicitação e a oferta precisa estar AVAILABLE e dentro do expires_at. Resposta 202:
assinatura, averbação e desembolso seguem em background.5. Acompanhar até o fim.#
Continue no mesmo GET: o status progride por CONTRACTING → AWAITING_SIGNATURE → SIGNED → ENDORSED → AWAITING_DISBURSEMENT → DISBURSED.Duas coisas que costumam pegar quem integra#
A chave de acompanhamento é o application_id, não o proposal_uuid. A proposta é criada
apenas no aceite e muda a cada nova tentativa de contratação: se o banco recusar e você aceitar
outra oferta, nasce outra proposta. Só o application_id atravessa o fluxo inteiro.Recusa do banco não é erro HTTP. Se o banco recusar a contratação, o POST /accept já terá
respondido 202 — a recusa chega depois, com a solicitação em CONTRACT_REJECTED e o motivo em
offers[].rejection_reason. E esse estado não é terminal: você pode aceitar outra oferta do
mesmo menu, desde que ainda esteja no prazo. Trate CONTRACT_REJECTED como "tente a próxima", não
como fim de linha.Quando as ofertas expiram#
Simulação de banco tem validade, e por isso expires_at é obrigatório em toda oferta. Hoje a
janela é de 1 hora a partir do momento em que a oferta entra no menu — tempo pensado para caber
apresentar as condições ao cliente, coletar o KYC e aceitar.Passado o prazo, o aceite responde 409 OFFER_EXPIRED. O caminho é POST
/applications/{id}/requote, que dispara uma nova rodada na mesma solicitação — as ofertas
anteriores são invalidadas, então descarte os offer_id antigos.Repare que a oferta vencida continua aparecendo como AVAILABLE no GET: o vencimento é aferido
no aceite, não gravado por um processo em background. Use o expires_at para decidir se ainda vale
apresentá-la.O requote sempre recota de verdade nas bancarizadoras; nunca devolve o resultado guardado de
uma cotação anterior do mesmo dia. É isso que faz o novo menu refletir mudanças de tabela, taxa ou
saldo ocorridas desde a rodada passada.O preço é que cada re-cotação consome o limite de simulações do CPF, e há dois desfechos quando ele
estoura. Se alguma bancarizadora ainda cotar, as que recusaram voltam sem oferta, com o motivo
em quotes[].reason, e a rodada segue com o que veio. Se todas recusarem, a chamada responde
429 RATE_LIMIT_EXCEEDED e nada muda — o menu anterior continua valendo, justamente para você
não ficar sem oferta nenhuma por ter tentado recotar cedo demais. Espere e repita a chamada.Dados de desembolso#
Os campos de bank no KYC são os que valem na contratação. Quais são obrigatórios depende de
disbursement_method:disbursement_method | Campos exigidos |
|---|
PIX | pix_key (e pix_type) |
BANK_ACCOUNT | bank_code, agency, account_number |
Nem toda bancarizadora suporta as duas formas. Como você não escolhe a bancarizadora — ela vem
com a oferta —, pode acontecer de a oferta aceita exigir uma forma que o KYC não atende. Nesse caso
o aceite responde 422 DISBURSEMENT_DATA_REQUIRED, e a mensagem diz exatamente o que falta:
complete o KYC e aceite de novo.Vincular a operação ao seu operador (user_uuid)#
A partir de 05/10/2026 às 00:00 (horário de Brasília), o user_uuid é obrigatório. A
abertura da solicitação sem ele passa a responder 422 VALIDATION_FAILED. Detalhes e prazo no
documento Changelog e avisos de mudança.
Sem o campo, a solicitação — e a proposta que nascer dela — fica vinculada ao usuário padrão da
API, que aparece na plataforma como "Originação (Sistema)". Com isso nenhum operador do seu
time aparece como usuário digitador da proposta, e a comissão não é atribuída a ninguém.Para vincular a operação a quem de fato a conduziu, informe o user_uuid desse operador na
abertura da solicitação:O vínculo vale para a solicitação inteira: o operador fica como dono dela e passa a ser o usuário
digitador da proposta contratada a partir dela. Não é preciso repetir o campo no KYC nem no aceite.Como obter o user_uuid#
O user_uuid é o identificador do operador na nossa plataforma, não no seu sistema. Busque-o
na API de usuários, filtrando pelo CPF (ou e-mail) do operador:Use o campo uuid do item retornado. O valor não muda: guarde o mapeamento
"operador do seu sistema → uuid" no seu cadastro e consulte a API só quando entrar um operador
novo. Se o operador ainda não existe na plataforma, cadastre-o com POST /api/v1/users.Regras#
Obrigatório a partir de 05/10/2026 00:00 (horário de Brasília). Até lá, sem o campo a
operação segue com o usuário padrão da API e a resposta 202 traz os headers Deprecation,
Sunset (a data do prazo) e Link (a explicação). Depois do prazo, a omissão responde
422 VALIDATION_FAILED com details[].field = "user_uuid" e details[].code = "REQUIRED", e a
solicitação não é aberta.
Scope users:read. A validação do operador usa a mesma leitura da API de usuários, então a
sua api-key precisa desse scope (além de proposals:write). Sem ele a abertura responde 422.
O operador precisa ser seu. Tem de ser um usuário ativo do seu parceiro ou de um
sub-parceiro abaixo dele. Usuário de outro parceiro, inexistente ou inativo responde
422 VALIDATION_FAILED, com details[].field = "user_uuid", e a solicitação não é aberta.
Faz parte da idempotência. O user_uuid entra na comparação do corpo: reenviar a mesma
Idempotency-Key com outro user_uuid responde 409, como qualquer outra mudança de corpo.
Sem infra de webhook? Sem problema#
O webhook é gatilho de conveniência; o GET é a fonte da verdade. O fluxo inteiro funciona só com
POST + GET, e o GET /applications/{id}/status existe justamente para tornar o polling barato.
Quem usa webhook também deve confirmar pelo GET antes de agir — um evento pode se perder, e o
GET sempre reconcilia. Modificado em 2026-10-01 02:47:11