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.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.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. 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.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.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-08-03 01:24:45