Contrato v1 (legado)
O corpo {event, data} que webhooks com contract_version = v1 recebem, com os valores de data.status e os dois campos que a IORQ acrescenta na entrega. Preservado na íntegra; integrações novas devem usar o v2.
Webhooks com contract_version = v1 seguem recebendo este corpo, sem mudança e sem data de corte nesta página. Integrações novas devem registrar contract_version = v2 e ler o Catálogo de eventos; a tabela de tipos de lá traz, em cada linha, o data.status equivalente desta página.
1. Envelope
Hoje a IORQ envia um único message_type: LOAN_UPDATE. O corpo do POST para a sua URL é o objeto payload acrescido de iorq_fund_id e event_timestamp no topo, com esta forma:
{
"event": "update",
"data": {
"entity_id": "<originator_proposal_code>",
"status": "<status — ver abaixo>",
"reason": "<motivo, quando aplicável>",
"nosso_numero": "<quando aplicável>",
"installment_code": "<quando aplicável>",
"banker_proposal_code": "<quando aplicável>",
"entity_type": "ccb",
"due_date": "<quando aplicável — nova data de vencimento (ISO)>"
},
"iorq_fund_id": "374485cf-f6df-467c-b91d-9f14082c6f36",
"event_timestamp": "2026-09-02T18:33:20.123456+00:00"
}O discriminador do que aconteceu é data.status. Os demais campos de data variam conforme o status e só aparecem quando há valor: são omitidos, não enviados como null. banker_proposal_code, por exemplo, só pode vir nos status ligados às suas chamadas e à cobrança (falhas de chamada, liquidação, antecipação, bolecode e alteração de vencimento); as decisões do gestor (approved, rejected e as de renegociação) e as confirmações da administradora (*_completed) nunca o trazem. Não há um evento por transição de estado — tudo chega como LOAN_UPDATE.
Um exemplo real de operação aprovada:
{
"event": "update",
"data": {
"entity_id": "OP-001",
"status": "approved",
"entity_type": "ccb"
},
"iorq_fund_id": "374485cf-f6df-467c-b91d-9f14082c6f36",
"event_timestamp": "2026-09-02T18:33:20.123456+00:00"
}2. Campos que a IORQ acrescenta na entrega
Dois campos no topo do corpo não vêm do payload do evento: a IORQ os injeta no momento da entrega. Ambos entram antes da assinatura, então o HMAC cobre o corpo já com eles. A validação não muda: calcule o digest sobre os bytes exatos recebidos (ver Configuração e segurança).
Consumidores que ignoram campos desconhecidos não precisam de nenhuma mudança. Se o seu parser rejeita campos extras (additionalProperties: false ou equivalente), libere os dois.
iorq_fund_id
iorq_fund_idO UUID do fundo a que o evento pertence, o mesmo informado no registro do webhook (header iorq-fund-id). Quem integra mais de um fundo pode rotear pelo próprio corpo, sem depender de uma URL distinta por fundo. O valor é o do evento registrado na IORQ: se o seu webhook está registrado para o fundo A, todo corpo entregue nele traz o iorq_fund_id do fundo A.
event_timestamp
event_timestampO instante em que a IORQ gerou o evento, ISO-8601 em UTC com offset (2026-09-02T18:33:20.123456+00:00).
- Não é o instante do envio. É o do evento, e por isso é estável: todas as tentativas de entrega do mesmo evento chegam com o mesmo
event_timestamp. Para saber quando aquelePOSTespecífico saiu, use o headerX-IORQ-Timestamp, que muda a cada tentativa. - Numa reentrega manual (replay), o valor é o do evento original, não o do momento do replay. Um replay pedido três dias depois não se apresenta como fato novo, e é assim que você distingue uma notificação nova de uma reconciliação tardia.
- Chega em toda entrega, inclusive nos webhooks sem
signing_secret, que não recebem os headers de assinatura. - Se você recebe mais de uma entrega do mesmo fato por ter mais de um webhook registrado no fundo, todas trazem o mesmo
event_timestamp.
Sobre o nome, sem o prefixoiorq_Diferente do
iorq_fund_id, este campo não carrega o prefixo. Ele é acrescentado pela IORQ na entrega, como o outro. Se opayloadque a sua originação envia já contém um campoevent_timestamp, o valor da IORQ substitui o seu no corpo entregue. Nenhum produtor IORQ deLOAN_UPDATEemite esse campo hoje, mas vale conferir do seu lado antes do go-live.
3. Valores de data.status
data.status
Breaking change:completedfoi substituído por um valor por fluxoA IORQ costumava enviar o literal
"completed"emdata.statuspara confirmar, pela administradora, a conclusão de quatro operações distintas, sem nenhum campo no payload que dissesse qual delas havia ocorrido. Isso mudou: cada fluxo agora envia seu próprio valor (settlement_completed,acquisition_completed,repurchase_completed,renegotiation_completed, listados abaixo). Se o seu integrador filtra pordata.status == "completed", atualize-o: esse valor não é mais enviado.
invaliddeixou de ser a falha de toda chamada, e você escolhe quando adotarO literal
"invalid"era também o valor de falha da liquidação, da antecipação e da recompra, e o payload não dizia de qual chamada a falha vinha: só a presença deinstallment_codee o texto dedata.reasonpermitiam inferir. Cada uma tem agora o seu valor:invalid_settlement,invalid_prepaymenteinvalid_repurchase, listados nas seções abaixo.O que o seu webhook recebe depende do campo
v1_failure_statusdele. Webhook registrado antes do campo existir está emshared_invalide continua recebendoinvalidnas três falhas, sem mudança. Quando o seu integrador estiver pronto para os três valores, troque comPATCH /api/webhook/{webhook_id}e{"v1_failure_status": "per_context"}; vale a partir da próxima entrega, e volta do mesmo jeito. Webhook novo nasce emper_context. Ver Configurando webhooks.
Cessão
status | Quando dispara |
|---|---|
approved | O gestor do fundo aprovou o lote de aquisição com a operação, e ela segue para a administradora. A elegibilidade aprovada na entrada não gera evento; só a reprovada (invalid) |
rejected | Operação recusada, esquemática ou de negócio (ver data.reason) |
invalid | Operação reprovou na validação e ficou em invalid. Em per_context, só a cessão usa este valor; em shared_invalid, também a falha de liquidação, antecipação e recompra chega assim |
Aquisição
status | Quando dispara |
|---|---|
acquisition_completed | Administradora confirma a aquisição; a operação passa a active e o lote a acquired |
Liquidação
status | Quando dispara |
|---|---|
settled_installment | Parcela liquidada, 1º tempo: a IORQ registrou o pagamento |
received_prepayment | Liquidação antecipada aceita |
settlement_completed | Baixa confirmada pela administradora, 2º tempo: a parcela vai a settled |
invalid_settlement | A liquidação notificada não foi aplicada (estado inválido, parcela não encontrada, conciliação); a parcela segue como estava, salvo em settlement_conciliation_error, que a marca nesse estado. Traz installment_code e, quando há boleto, nosso_numero; ver data.reason |
invalid_prepayment | O pedido de antecipação não foi aceito; nenhuma parcela mudou. installment_code é o code do lote; ver data.reason |
Pós-cessão
status | Quando dispara |
|---|---|
approved | Recompra aprovada pelo gestor. É o mesmo valor da aprovação de cessão: no v1 os dois fatos não se distinguem, e no v2 são loan.approved e repurchase.approved. A mesma operação pode receber approved duas vezes, a da cessão e depois a da recompra; ver o aviso abaixo |
rejected | Recompra recusada, ou renegociação recusada manualmente pelo gestor antes de qualquer aprovação. Mesma observação: no v2 são loan.rejected e repurchase.rejected |
approved_renegotiation | Renegociação aprovada, com a nova operação na carteira |
rejected_renegotiation | Ao aprovar um lote de renegociação, a operação não chegou a approved_renegotiation nem é inválida. Distinto do rejected acima, que é a rejeição manual anterior a qualquer aprovação |
invalid_renegotiation | Falha na renegociação |
invalid_repurchase | O pedido de recompra não foi aceito (loan_not_found, invalid_loan_state, value_mismatch nos fundos cuja recompra confere o valor); a operação segue como estava; ver data.reason |
repurchase_completed | Administradora confirma a recompra; a operação vai a repurchased |
renegotiation_completed | Administradora confirma a renegociação; a nova operação vai a active e a antiga a renegotiated |
approvedpode chegar duas vezes para a mesma operaçãoA aprovação da recompra chega com o mesmo corpo da aprovação da cessão:
status: approvedpara o mesmoentity_id; o mesmo vale pararejected. O v1 não distingue os dois fatos. Uma deduplicação porentity_id+statusdescarta a aprovação da recompra como repetida. Trate umapprovedde uma operação que já está na carteira e para a qual você pediuPOST /loan/repurchasecomo a decisão da recompra e confirme consultando a operação, ou migre para o v2, que entregarepurchase.approved.
Bolecode
status | Quando dispara |
|---|---|
issued_bolecode | Boleto emitido para a parcela ou para o lote de antecipação; traz nosso_numero, installment_code e banker_proposal_code |
canceled_bolecode | Boleto cancelado, por exemplo quando a parcela é substituída por recompra ou renegociação |
Alteração de vencimento
status | Quando dispara |
|---|---|
due_date_changed | Nova data de vencimento em vigor no boleto da parcela, um webhook por parcela, com a data em data.due_date e a parcela em data.installment_code |
O due_date_changed só é emitido quando a cobrança da operação é de responsabilidade da IORQ: sem boleto IORQ, a alteração é registrada só na administradora e não gera evento. Ver Alteração de vencimento.
Teste
status | Quando dispara |
|---|---|
test | Você pediu um evento de teste em POST /api/webhook/{webhook_id}/test; entity_id é o fund_id e não há mais campos em data |
4. data.reason
data.reasonEm status de recusa ou falha, data.reason traz o motivo, e pode ser uma string ou um objeto:
- String nos motivos operacionais (
fund_not_found,loan_not_found for originator=... banker=None,invalid_installment_state,value_mismatch (...)). - String com um JSON dentro nos critérios
E0xxemitidos fora do lote: a elegibilidade na entrada da cessão (invalid) e da renegociação (invalid_renegotiation), a expiração da renegociação pré-aprovada (E023) e o documento de renegociação reprovado (E024). O valor é o mapa{"E0xx": {"title", "description"}}serializado:"reason": "{\"E023\": {\"title\": \"Renegociação Expirada\", ...}}". Parseie a string para ler os códigos. - Objeto
{"E0xx": {"title", "description"}}nosE0xxdo lote de renegociação (invalid_renegotiation) e noE026da reprovação em covenant (rejected).
Os textos são estáveis por compatibilidade, não por contrato: o código por trás de cada string está no catálogo de códigos de erro, e no v2 ele chega estruturado em errors[].code.
5. Sem filtro por tipo de evento
Um webhook v1 recebe todos os LOAN_UPDATE do fundo. O event_types do registro só filtra fatos que o produtor já publica em v2; até a virada, o filtro é feito no seu lado, pelo data.status.
6. Deduplicação
O corpo v1 não traz identificador do evento. Deduplique pelo conteúdo de data (entity_id + status, mais installment_code e due_date quando existirem), prefixado pelo iorq_fund_id, com a exceção do approved/rejected da recompra descrita na seção 3. A receita está em Idempotência e reentrega.
7. Próximos passos
Updated about 1 month ago
