# QI Tech — Crédito Consignado › Exército

Documentação da QI Tech em texto corrido, para colar em um LLM.
Fonte: https://docs.qitech.com.br
11 página(s).

Índice:
- Assinatura em Lote (/documentation/manual_exercito/assinatura-em-lote)
- Cancelamento, Desaverbação e Reversal (/documentation/manual_exercito/cancelamento)
- Consulta de Margem Consignável (/documentation/manual_exercito/consulta-margem)
- Conta Interna para Desembolso (/documentation/manual_exercito/conta-interna-desembolso)
- Modelos de Formalização (/documentation/manual_exercito/formalizacao)
- Consignado do Exército — Introdução (/documentation/manual_exercito/introducao)
- Mapa de Status (/documentation/manual_exercito/mapa-de-status)
- Margem Livre (Crédito Novo) (/documentation/manual_exercito/margem-livre)
- Mocks (Sandbox) (/documentation/manual_exercito/mocks-sandbox)
- Portabilidade + Refinanciamento (/documentation/manual_exercito/portabilidade-refin)
- Webhooks (/documentation/manual_exercito/webhooks)

---

# Assinatura em Lote

URL: /documentation/manual_exercito/assinatura-em-lote

Agrupa **várias operações do consignado militar** em **um único envelope** de assinatura do QI Sign. Você abre o lote, cria as operações referenciando o `document_batch_key`, confere (opcionalmente limpa) e dispara o envio para assinatura.

Fluxo recomendado para [compra de dívida](./04-portabilidade-refin.md) — onde N duplas `debt_purchase` + `refinancing` + 1 refin/refin consolidador podem ser assinadas num único envelope (militar assina uma vez só).

:::caution Regras do lote
**Mesma titularidade:** todas as operações do lote devem ser do **CPF** (ou do **mesmo representante legal**) do militar. Incluir CPF "A" e CPF "B" no mesmo lote gera **erro síncrono** no `POST /debt`.

**Tipos permitidos:** o lote do Exército aceita apenas `POST /debt` com `collateral_type: military_payroll`.
:::

## 1. Abrir o lote

ENDPOINT /document/document_batch
MÉTODO POST

**Request Body**

```json
{
  "type": "military_payroll_external_batch",
  "certifier_type": "qi_sign",
  "batch_name": "Lote EB compra-divida - 5ed20003-0610-46d2-88cc-a5d0de640696",
  "request_control_key": "5ed20003-0610-46d2-88cc-a5d0de640696"
}
```

### Campos chave

| Campo | Tipo | Descrição |
|---|---|---|
| `type` | string | Fixo: **`military_payroll_external_batch`** |
| `certifier_type` | string | Fixo: **`qi_sign`** |
| `batch_name` | string | Nome identificador do lote (**máximo 100 caracteres**) |
| `request_control_key` | string (UUIDv4) | **Idempotência** — não reutilize entre lotes |

**Response Body**

```json
{
  "document_batch_key": "17f35e19-a039-468f-aaa7-84aa8edec3dc"
}
```

Guarde o `document_batch_key` retornado — ele é referenciado em todas as próximas chamadas.

## 2. Incluir operações no lote

Ao criar cada operação militar, envie **`document_batch_key` na raiz** do payload do `POST /debt` (mesmo nível dos demais campos principais).

ENDPOINT /debt
MÉTODO POST

```json
{
  "document_batch_key": "17f35e19-a039-468f-aaa7-84aa8edec3dc",
  "borrower": { "...": "demais campos do borrower" },
  "financial": { "...": "demais campos financeiros" },
  "operation_type": "refinancing",
  "collaterals": [
    {
      "collateral_type": "military_payroll",
      "collateral_data": {
        "reservation_type": "refinancing",
        "registration_code": "146254221",
        "token": "12345678"
      }
    }
  ],
  "modality": { "code": "0202" },
  "refinanced_credit_operations": [
    { "...": "operation_key + contrato externo (ver Portabilidade + Refin)" }
  ]
}
```

O restante do body segue o contrato do `POST /debt`. Consulte os roteiros da [Margem Livre](./03-margem-livre.md) ou [Portabilidade + Refinanciamento](./04-portabilidade-refin.md) conforme a modalidade.

:::tip Compra de dívida cabe num lote só
Pra [compra de dívida](./04-portabilidade-refin.md) (`debt_purchase` + `refinancing` port-enrustido), todas as duplas Op A + Op B + o refin/refin consolidador podem entrar no mesmo lote.
:::

## 3. Consultar documentos do lote

Recomendado **antes de fechar o lote** para conferir os documentos agrupados.

ENDPOINT /document/document_batch/DOCUMENT_BATCH_KEY
MÉTODO GET

**Response Body**

```json
{
  "document_batch_key": "1eee4ec2-05f5-45ef-aa64-38bb3d9de02f",
  "documents": [
    {
      "document_key": "5cca1dad-28fe-4f19-8bbb-0edd6f042384",
      "document_type": "ccb_pre_price_days"
    },
    {
      "document_key": "c109d589-ae18-4f4f-ad31-2879bf714c71",
      "document_type": "ccb_pre_price_days"
    }
  ]
}
```

## 4. Limpar documentos do lote (opcional)

Remove **todos os documentos** vinculados ao lote — útil pra reagrupar do zero se identificar inconsistência antes do envio.

ENDPOINT /document/document_batch/DOCUMENT_BATCH_KEY/documents
MÉTODO DELETE

Body vazio. Response: HTTP 200.

## 5. Enviar para assinatura

Fecha o lote e dispara os documentos pro QI Sign. **Antes desse PUT, os documentos não vão pro militar.** É o gatilho final.

ENDPOINT /document/document_batch/DOCUMENT_BATCH_KEY/send_to_signature
MÉTODO PUT

Body: `{}`. Response: HTTP 200.

## Erros comuns

| HTTP | Código | Endpoint | Quando ocorre |
|---|---|---|---|
| 404 | `DOC000007` | `GET /document/document_batch/DOCUMENT_BATCH_KEY` | `document_batch_key` inexistente |
| 409 | `DOC000103` | `POST /document/document_batch` | `request_control_key` duplicado (idempotência violada) |

**Exemplo — DOC000103 (idempotência)**

```json
{
  "code": "DOC000103",
  "title": "Bad Request",
  "description": "request_control_key already exists",
  "translation": "Chave de controle da request já existe.",
  "http_status": 409
}
```

:::info Conflito de titularidade
Validação de **mesmo CPF/representante** no lote retorna erro no `POST /debt` (não no endpoint do lote). O corpo de erro segue o catálogo do `/debt`.
:::

---

# Cancelamento, Desaverbação e Reversal

URL: /documentation/manual_exercito/cancelamento

Cancelar uma operação militar tem dois eixos independentes:
1. **Cancelamento da CCB** — estado da operação no LaaS, e eventual estorno do dinheiro desembolsado.
2. **Desaverbação no Zetra** — liberação da margem em folha de pagamento.

Os dois acontecem de forma assíncrona e nem sempre simultâneos. Cancelar a operação NÃO libera a margem instantaneamente; pagar de volta o dinheiro desembolsado também é um passo separado.

## 1. Pré-desembolso — Cancelamento Imediato

Antes do desembolso (operação em `waiting_signature`, `signature_finished` ou `waiting_disbursement`):

```http
PATCH /debt/{DEBT_KEY}/cancel
```

Sem body. Resposta imediata: operação vai pra `canceled`. Não há reversal financeiro (dinheiro nem saiu).

Webhook: `debt` com `status: canceled` + `cancel_reason_enumerator` indicando o motivo (`manual`, `waiting_signature`, `not_collateral_constituted`, etc.).

A QI dispara em seguida a desaverbação no Zetra (ver seção 4).

## 2. Pós-desembolso — Janela de Desistência (7 dias úteis)

**A janela legal de desistência é de 7 dias úteis** após o desembolso. Dentro dela:

```http
PATCH /debt/{DEBT_KEY}/cancel
```

A response **NÃO é instantânea como o pré-desembolso** — retorna um **PIX QR Code** que o borrower deve pagar pra devolver o dinheiro desembolsado. O parceiro repassa o QR pro cliente.

| Campo na response | Significado |
|---|---|
| `cancel_qr_code.qr_code_url` / `digitable_line` | PIX copia-e-cola ou QR pra pagamento |
| `cancel_qr_code.amount` | Valor a devolver (igual ao desembolsado) |
| `cancel_qr_code.expiration` | Prazo pro pagamento (15 dias úteis após desembolso) |

Quando o borrower paga o PIX:
1. QI confirma o pagamento.
2. Dispara o **reversal financeiro automático** — desfaz o desembolso, devolve pro fundo.
3. Webhook `reversal` chega:
   ```json
   {
     "webhook_type": "reversal",
     "credit_operation_key": "<uuid>",
     "contract_number": "<...>",
     "reversal": {
       "status": "pending_fund",
       "amount": 2026.93,
       "amount_to_send": 2026.93,
       "is_total": true,
       "is_operation_canceled": true,
       "reversal_key": "<uuid>",
       "date": "2026-09-06"
     }
   }
   ```
4. QI dispara a desaverbação no Zetra.
5. Operação vai pra `canceled`.

> [!warning] Prazo de pagamento do QR
> O QR tem validade de **15 dias úteis após o desembolso** (não após emissão do QR). Se o borrower não pagar dentro desse prazo, o cancelamento expira e a operação volta a ser ativa — vira inadimplência normal (cobrança de parcelas segue o curso).

Restrições pós-desembolso:
- Operação precisa estar em status `open` (sem parcelas pagas).
- Pagamento parcial de qualquer parcela bloqueia o cancelamento.
- Não há cancelamento parcial — só total.

## 3. Cancelamento Permanente

```http
PATCH /debt/{DEBT_KEY}/cancel/permanent
```

Marca como `canceled_permanently` — não há volta. Útil pra:
- Cliente desistiu e não vai pagar o QR (vira inadimplência → permanent depois)
- Operação que ficou pendente além do prazo (auto-cancel já faz isso em 7 dias, mas pode forçar)

Sem reversal automático — usar apenas se o dinheiro já foi resolvido por fora ou nunca saiu.

## 4. Desaverbação no Zetra

Independente do cancelamento financeiro, a desaverbação é processada pelo Zetra de forma assíncrona:

![Fluxo de cancelamento Exército](/img/diagrams/exercito-cancelamento.svg)

| Status no `credit_operation.collateral` | Significado |
|---|---|
| `waiting_confirmation` | Zetra ainda processando a desaverbação |
| `successfully_deleted` | Margem liberada |
| `communication_error` | Zetra indisponível (cod 241) — QI retenta automaticamente |

> [!warning]
> **Não considere a margem liberada até `successfully_deleted` chegar.** Emitir nova operação no mesmo militar antes da desaverbação confirmada retorna `consignable_margin_exceeded`.

Pra consultar o estado:

```http
GET /debt/{DEBT_KEY}/collateral
```

Retorna `last_response` + `reservation_status` atual.

## 5. Auto-cancelamento (7 dias)

Operações em status `canceled` (não-permanente) por mais de **7 dias** são automaticamente convertidas em `canceled_permanently` pelo sistema. Aplica-se a:
- Operação cuja averbação foi recusada (`consent_refused`)
- Operação cuja averbação expirou (`consent_expired`)
- Operação pendente de assinatura além do prazo
- Operação com cancelamento solicitado mas QR não pago dentro de 15 dias úteis

Não precisa fazer nada — o sistema cancela e desaverba sozinho.

## Resumo dos Endpoints

| Endpoint | Quando usar | Reversal automático? |
|---|---|---|
| `PATCH /debt/{KEY}/cancel` (pré-desembolso) | Antes do desembolso | Não aplica (dinheiro não saiu) |
| `PATCH /debt/{KEY}/cancel` (pós-desembolso) | Dentro de 7 dias úteis após desembolso | Sim — após borrower pagar o PIX QR retornado |
| `PATCH /debt/{KEY}/cancel/permanent` | Cancelamento definitivo (sem volta) | Não — uso administrativo |

## Cancel reasons no webhook `debt` (`status: canceled`)

Os principais `cancel_reason_enumerator` que aparecem:

| Enumerador | Significado |
|---|---|
| `manual` | Cancelado via API ou portal |
| `waiting_signature` | Não assinou no prazo |
| `not_collateral_constituted` | Averbação falhou |
| `is_portability` | Portabilidade falhou |
| `pix_max_retry` | Muitas falhas no desembolso PIX |
| `lack_of_resource` | Sem recurso pra desembolsar |
| `kyc_not_accepted` | KYC reprovado |

→ [Lista completa de enumeradores em Mapa de Status](./08-mapa-de-status.md)

---

# Consulta de Margem Consignável

URL: /documentation/manual_exercito/consulta-margem

Endpoint que consulta a margem disponível do militar no Zetra (eConsig). É o **primeiro passo operacional** depois do upload da autorização — sem o `balance_key` desse passo, não dá pra simular nem emitir.

## Pré-requisitos

1. **Upload do consentimento** feito (`POST /upload` → `document_key`). → [Upload de Documentos](../upload_de_documentos/)
2. **Token Zetra** do militar em mãos (senha do sistema militar).

## Endpoint

```http
POST /military_payroll/balance
```

| Campo | Tipo | Descrição |
|---|---|---|
| `document_number` | string | CPF do militar — 11 dígitos, sem `.` e sem `-`, zero-padded |
| `registration_code` | string | Matrícula do militar |
| `authorization_document_key` | uuid | `document_key` retornado no upload |
| `token` | string | Token de autenticação Zetra (senha) |

Resposta síncrona:

```json
{
  "balance_key": "81da8afb-e1b2-4215-8093-c4b5feab8a9f",
  "status": "pending_search"
}
```

## Webhook de resultado

Tipo: `military_payroll.balance.status_change`

Campos no payload de **sucesso**:
- `balance` — margem disponível (Decimal)
- `allowed_installment_numbers` — array de prazos válidos (ex: `[24, 36, 48]`)
- `military_unit` — unidade do militar
- `military_branch` — força (string longa, dezenas de valores possíveis: `AMAN`, `Sistema de Retribuição do Exterior`, etc.)
- `category` — `ATIVO`, `INATIVO`, `PENSIONISTA`
- `name`, `document_number`, `registration_code`, `birth_date`, `grant_date`

## Enumeradores de falha

| Enumerador | Zetra code | Significado | Ação |
|---|---|---|---|
| `invalid_registration_code` | 210 | Matrícula inválida ou inexistente | Verificar matrícula |
| `military_not_found` | 293 | Militar não encontrado pelo CPF+matrícula | Verificar dados |
| `military_blocked` | 352 | Militar com bloqueio em folha | Não há ação imediata |
| `communication_error` | 241 | Zetra indisponível | QI retenta automaticamente |

## Sandbox

A sandbox militar **conecta na Zetra real de homologação** (`central_homologa.econsig.com.br`) — não há whitelist local de CPFs no `military-payroll-api`. Os dados de teste (CPFs, matrículas, tokens) são fornecidos pela Zetra.

Solicite ao time de Integrações QI Tech a lista de servidores fictícios disponíveis. CPFs fora dessa lista retornam `military_not_found` (Zetra 293) ou `invalid_registration_code` (Zetra 210).

→ [Mocks (Sandbox) — detalhes completos](./09-mocks-sandbox.md)

## Próximo passo

Após o webhook `succeeded` com `balance` retornado, escolha a modalidade:

- [Margem Livre](./03-margem-livre.md) — crédito novo com margem disponível
- [Portabilidade + Refinanciamento](./04-portabilidade-refin.md) — refin de operação QI ou compra de dívida externa

---

# Conta Interna para Desembolso

URL: /documentation/manual_exercito/conta-interna-desembolso

Em **compra de dívida**, **portabilidade** e **refinanciamento** do consignado militar (Exército), o desembolso da operação **não vai direto para a conta externa do tomador**: ele cai numa conta interna **em nome do tomador** (aberta pelo parceiro via `POST /account`). É a partir dessa conta que a QI executa as ações pós-desembolso — **quitação do contrato externo**, **repasse de troco**, **conciliação**.

:::tip Por que conta interna?
Concentrar o desembolso numa conta operacional dá controle do fluxo: a QI consegue orquestrar quitação externa + averbação + repasse de troco sem depender de SLA de banco terceiro no meio do processo.
:::

## Quando usar conta interna vs externa

| Cenário | `disbursement_bank_account` |
|---|---|
| [Margem Livre](./03-margem-livre.md) (crédito novo direto) | Conta **externa** do tomador |
| [Refinanciamento puro](./04-portabilidade-refin.md) (renegocia CO QI ativa) | Conta **interna** em nome do tomador |
| [Portabilidade](./04-portabilidade-refin.md) (com ou sem troco) | Conta **interna** em nome do tomador |
| [Compra de dívida](./04-portabilidade-refin.md) (`debt_purchase` + `refinancing` port-enrustido) | Conta **interna** em nome do tomador **nas duas operações da dupla** |
| Refin/refin consolidador (opcional, fecha várias port/refins) | Conta **interna** em nome do tomador |

## 1. Abrir a conta interna em nome do tomador

ENDPOINT /account
MÉTODO POST

A conta é aberta pelo **parceiro** (autenticado com seus `client_integration_key`), com o `owner_document_number` apontando para o **CPF do militar tomador**. Reutilize a conta existente — uma por tomador (não abrir nova a cada operação).

**Request Body**

```json
{
  "owner_document_number": "<CPF DO MILITAR>",
  "owner_person_key": "<PERSON_KEY DO MILITAR>",
  "requester_key": "<REQUESTER_KEY DO PARCEIRO>",
  "webhook_enabled": true
}
```

:::info Pré-requisito
O militar precisa estar **onboarded** previamente (ter `person_key`) — o parceiro envia esse `person_key` no `owner_person_key`. Caso contrário, o `/account` falha com `ACC000xxx` por validation.
:::

**Response Body**

```json
{
  "account_key": "1167955-...",
  "account_branch": "0001",
  "account_number": "1167955",
  "account_digit": "1",
  "owner_document_number": "<CPF DO MILITAR>",
  "owner_name": "<NOME DO MILITAR>",
  "bank_code": "329",
  "account_status": "active",
  "webhook_enabled": true
}
```

:::tip Idempotência por tomador
Se já existe conta ativa para esse `owner_document_number` no parceiro, evite chamar `POST /account` de novo — consulte `GET /accounts?owner_document_number= ` antes e reaproveite o `account_key` retornado.
:::

## 2. Usar a conta no `/debt`

Use os dados retornados em `disbursement_bank_account` no payload do `POST /debt`. **A mesma conta vai nas DUAS operações da dupla `debt_purchase` + `refinancing`** (e no `refinancing` consolidador, se houver).

```json
{
  "disbursement_bank_account": {
    "name": "<NOME DO MILITAR>",
    "bank_code": "329",
    "account_type": "checking_account",
    "account_branch": "0001",
    "account_number": "1167955",
    "account_digit": "1",
    "document_number": "<CPF DO MILITAR>",
    "transfer_method": "ted"
  }
}
```

| Campo | Valor (conta interna QI Tech) |
|---|---|
| `bank_code` | `"329"` (QI Tech S.A. — SCD) |
| `account_branch` | `"0001"` |
| `account_number` / `account_digit` | retornados no `POST /account` |
| `document_number` | **CPF do militar** (mesmo do `owner_document_number`) |
| `transfer_method` | `"ted"` (recomendado para `payment_type_id: 10`) |

Exemplo completo: ver [Portabilidade + Refinanciamento — Compra de dívida](./04-portabilidade-refin.md).

## 3. Ações pós-desembolso

A QI dispara as ações abaixo automaticamente conforme os webhooks confirmam cada etapa.

### 3.1 Conferir saldo

ENDPOINT /account/ACCOUNT_KEY/balance
MÉTODO GET

### 3.2 Quitação do contrato externo (port)

Disparada pela QI ao receber `credit_operation.collateral` (`reservation_status: deleted`) na operação antiga: saldo da conta interna é enviado ao banco origem via **PIX** ou **TED** para liquidar o contrato externo.

### 3.3 Repasse de troco pro tomador (se houver)

Se `final_disbursement_amount > 0` na simulação, o saldo residual é transferido da conta interna para a **conta externa do militar** (informada no onboarding ou no payload da operação).

### 3.4 Conciliação

ENDPOINT /account/ACCOUNT_KEY/statement
MÉTODO GET

Query params `from_date` e `to_date` no formato `YYYY-MM-DD`.

### 3.5 Webhooks relevantes

| Webhook | Quando dispara |
|---|---|
| `account.balance_change` | Crédito recebido na conta interna (desembolso da CO) |
| `pix_transfer.status_change` | Quitação externa OU repasse de troco confirmados |
| `ted.status_change` | Quitação externa OU repasse via TED confirmados |

## Referências

- [Conta de pagamento — fluxo completo](/documentation/contas/abertura_de_conta/fluxo_de_abertura_de_conta) — referência do `POST /account` em detalhes
- [Portabilidade + Refinanciamento](./04-portabilidade-refin.md) — usa essa conta em compra de dívida (`debt_purchase` + `refinancing`)
- [Webhooks](./07-webhooks.md) — eventos assíncronos da operação

---

# Modelos de Formalização

URL: /documentation/manual_exercito/formalizacao

A QI Tech suporta **5 modelos** de formalização da operação militar — escolha conforme a infraestrutura do parceiro (se já tem signature provider, se quer usar QI Sign, se vai usar biometria). Adicionalmente, pra agrupar várias operações num único envelope (recomendado em [compra de dívida](./04-portabilidade-refin.md)), use [Assinatura em Lote](./11-assinatura-em-lote.md).

:::tip Várias operações no mesmo envelope
Em compra de dívida com N duplas `debt_purchase` + `refinancing` (+ refin/refin consolidador), use [Assinatura em Lote](./11-assinatura-em-lote.md) (`POST /document/document_batch` com `type: military_payroll_external_batch`) — o militar assina tudo de uma vez só.
:::

## Modelos disponíveis

| Modelo | Quando usar |
|---|---|
| **QI Sign automático** (default) | Não precisa configurar nada — QI envia link de assinatura por email/SMS pro borrower |
| **QI Sign em lote** | Várias operações num único envelope; ver [Assinatura em Lote](./11-assinatura-em-lote.md) |
| **PDF assinado externamente** | Parceiro tem signature provider próprio; faz upload do PDF assinado |
| **Data-signature: opt-in** | Borrower clica "concordo" em um portal do parceiro; parceiro envia evidência |
| **Data-signature: zip** | Parceiro envia zip com evidências (logs, IPs, timestamps) |
| **Data-signature: selfie** | Biometria via CaaS (face match + liveness) |

## QI Sign Automático

Não requer chamada adicional após `/debt`. QI envia URL de assinatura pro borrower (email/SMS). Quando o borrower assina, webhook `debt` fires com `status: signature_finished` e a esteira segue.

Pré-requisito: o RequesterConfiguration tem `default_signature_method` apontando pra QI Sign.

## PDF assinado externamente

```http
POST /debt/{DEBT_KEY}/signed
```

```json
{
  "signed_document_key": "<uuid retornado pelo upload do PDF assinado>"
}
```

Pré-requisito: fazer upload do PDF assinado via `POST /upload` antes de chamar `/signed`.

## Data-signature: opt-in

```json
{
  "data_signature": {
    "type": "opt_in",
    "evidence": {
      "ip_address": "200.123.45.67",
      "user_agent": "Mozilla/5.0 ...",
      "timestamp": "2026-05-17T14:30:00Z"
    }
  }
}
```

## Data-signature: zip

Parceiro empacota evidências em `.zip` e envia via upload. O `signed_document_key` aponta pro zip.

## Data-signature: selfie

Requer integração com CaaS (face recognition + liveness). O `signed_document_key` aponta pra um `image_key` retornado pelo CaaS.

## Webhook após formalização

`debt` com `status: signature_finished` → indica que QI aceitou a formalização. Em seguida, a averbação é confirmada (se `reservation_method: issuing`) e o desembolso entra na fila.

## Próximo passo

Após o `signature_finished`, a operação segue automaticamente: averbação confirmada (se `issuing`) → desembolso PIX/TED → webhook `debt` (`disbursed`).

Para acompanhar via webhooks: [Webhooks](./07-webhooks.md). Para cancelar a qualquer momento: [Cancelamento](./06-cancelamento.md).

---

# Consignado do Exército — Introdução

URL: /documentation/manual_exercito/introducao

API para originação de **CCB consignado** para militares do Exército Brasileiro (ativos, inativos e pensionistas). A reserva de margem é feita via **Zetra (eConsig)** e o ciclo todo — consulta de margem, emissão, averbação, desembolso e cancelamento — passa por essa plataforma.

| Item | Valor |
|---|---|
| Autoridade pagadora | Exército Brasileiro / **Zetra (eConsig)** |
| Tipo de garantia (`collateral_type`) | `military_payroll` |
| Modelo de reserva | Averbação (assíncrona, consentida via documento de autorização) |
| Funcionamento | **24h por dia, todos os dias, inclusive feriados** |
| Modalidades suportadas | [Margem Livre (Crédito Novo)](./03-margem-livre.md) e [Portabilidade + Refinanciamento](./04-portabilidade-refin.md) |
| Token | **Obrigatório** na consulta de margem (senha do sistema militar) |
| Instrumento | CCB (via `POST /debt`) |

:::danger Atenção!
Os webhooks da QI Tech não devem ser mapeados de forma restrita.
Campos adicionais podem ser incluídos aos payloads dos webhooks retornados em nossas APIs.
:::

:::info Reenvio de Webhooks
Você pode consultar e reenviar webhooks seguindo as instruções detalhadas na documentação: [Reenvio de Webhooks](/documentation/notificacoes/reenvio_de_notificacoes).
:::

## Fluxo End-to-End

Em **margem livre** o desembolso vai direto pra conta externa do militar. Em **refinanciamento, portabilidade e compra de dívida** o desembolso vai pra uma **conta interna em nome do militar** (aberta pelo parceiro via `POST /account`) — daí a QI quita o contrato externo, repassa o troco e faz a conciliação. Ver [Conta Interna para Desembolso](./10-conta-interna-desembolso.md).

![Fluxo end-to-end Exército](/img/diagrams/exercito-introducao.svg)

## Modalidades

A operação se divide em quatro modalidades, escolhidas no `operation_type` e `collateral_data`:

| Modalidade | `operation_type` / `reservation_type` | Quando usar | Doc |
|---|---|---|---|
| **Margem Livre** (Crédito Novo) | `operation_type: structured_operation` / `reservation_type: new_credit` | Militar com margem disponível; sem dívida externa nem refin de operação ativa | [→ Margem Livre](./03-margem-livre.md) |
| **Refinanciamento** | `operation_type: refinancing` / `reservation_type: refinancing` + `operation_key` | Renegociar operação QI ativa (prazo/taxa), eventualmente liberando troco | [→ Port + Refin](./04-portabilidade-refin.md) |
| **Portabilidade** (com ou sem troco) | `operation_type: refinancing` / `reservation_type: refinancing` + `original_contract_number` | Trazer dívida de outro banco; pode incluir troco | [→ Port + Refin](./04-portabilidade-refin.md) |
| **Compra de dívida** (port enrustida) | `operation_type: debt_purchase` + `operation_type: refinancing` (dupla) | Trazer N dívidas externas; QI emite uma dupla `debt_purchase` + `refinancing` por contrato externo, com desembolso em [conta interna em nome do militar](./10-conta-interna-desembolso.md) | [→ Port + Refin](./04-portabilidade-refin.md) |

## Pré-requisitos

Antes de qualquer requisição (Consulta, Emissão, etc):
1. Upload do consentimento do militar via `POST /upload` → retorna `document_key`. Ver [Upload de Documentos](../upload_de_documentos/).
2. Conhecer o **token** (senha do sistema militar Zetra) do borrower — é obrigatório no payload de `POST /military_payroll/balance`.

## Referência por área

- [Consulta de Margem](./02-consulta-margem.md) — endpoint `/military_payroll/balance` + token Zetra
- [Margem Livre](./03-margem-livre.md) — Simulação + Emissão para `new_credit`
- [Portabilidade + Refinanciamento](./04-portabilidade-refin.md) — Simulação + Emissão para `refinancing` + payloads de compra de dívida (`debt_purchase` + `refinancing` port-enrustido)
- [Formalização](./05-formalizacao.md) — 5 modelos: QI Sign, PDF, opt-in, zip, selfie
- [Conta Interna para Desembolso](./10-conta-interna-desembolso.md) — POST `/account` em nome do militar + uso em compra de dívida + ações pós-desembolso
- [Assinatura em Lote](./11-assinatura-em-lote.md) — agrupar várias operações num único envelope QI Sign (`POST /document/document_batch`)
- [Cancelamento, Desaverbação e Reversal](./06-cancelamento.md) — pré + pós-desembolso + reversal automático
- [Webhooks](./07-webhooks.md) — todos os eventos assíncronos + payloads
- [Mapa de Status](./08-mapa-de-status.md) — enumeradores consolidados
- [Mocks (Sandbox)](./09-mocks-sandbox.md) — dados de teste e cenários end-to-end

---

# Mapa de Status

URL: /documentation/manual_exercito/mapa-de-status

Referência consolidada de todos os enumeradores que podem aparecer nas respostas síncronas e webhooks do produto consignado militar.

## Consulta de Margem (`military_payroll.balance.status_change`)

| Status | Significado |
|---|---|
| `pending_search` | Resposta síncrona — consulta enfileirada no Zetra |
| `succeeded` | Webhook — margem retornada com sucesso |
| `failed` | Webhook — falha (ver `failure_reason`) |

### Failure reasons

| Enumerador | Zetra code | Significado |
|---|---|---|
| `invalid_registration_code` | 210 | Matrícula inválida |
| `military_not_found` | 293 | CPF/matrícula sem registro |
| `military_blocked` | 352 | Militar com bloqueio em folha |
| `communication_error` | 241 | Zetra indisponível |
| `invalid_document_number` | — | CPF malformado |

## Averbação / Desaverbação (`credit_operation.collateral`)

| Enumerador | `reservation_status` | Significado |
|---|---|---|
| `successfully_accepted` | `pending_confirmation` | Zetra aceitou a requisição, aguardando confirmação |
| `successfully_reserved` | `reserved` | Margem reservada com sucesso |
| `successfully_deleted` | `deleted` | Margem desaverbada com sucesso |
| `waiting_confirmation` | — | Aguardando Zetra |
| `communication_error` | — | Erro de comunicação (cod 241) |
| `consignable_margin_exceeded` | — | Margem insuficiente (cod 359) |
| `consent_refused` | — | Militar recusou o consentimento |
| `consent_expired` | — | Janela de consentimento expirou |
| `expired_portability` | — | Janela de port expirou |
| `origin_contract_not_found` | — | Contrato origem (port/refin) não existe |
| `waiting_for_origin_contract_closure` | — | Aguardando quitação externa |

## Operação (`debt`)

| Status | Significado |
|---|---|
| `waiting_signature` | Aguardando assinatura |
| `signature_finished` | Assinatura concluída |
| `waiting_disbursement` | Aguardando desembolso |
| `disbursed` | Desembolsado |
| `canceled` | Cancelada (não-permanente, ainda recuperável) |
| `canceled_permanently` | Cancelada definitivamente |
| `settled` | Liquidada (todas as parcelas pagas) |

### Cancel reasons (`cancel_reason_enumerator`)

| Enumerador | Significado |
|---|---|
| `manual` | Cancelado via API ou portal |
| `waiting_signature` | Não assinou no prazo |
| `not_collateral_constituted` | Averbação falhou |
| `is_portability` | Portabilidade falhou |
| `pix_max_retry` | Muitas falhas no desembolso PIX |
| `lack_of_resource` | Sem recurso pra desembolsar |
| `kyc_not_accepted` | KYC reprovado |
| `agencia_conta_invalida` | Erro em dados bancários |
| `invalid_account` | Conta inválida |
| `rejected_payment` | Pagamento recusado pelo banco destino |
| `disbursing_error` | Erro genérico no desembolso |
| `entry_not_paid` | Entrada não paga (refin com troco negativo) |
| `bank_slip_paid` | Boleto já foi pago |
| `unsupported_transaction` | Tipo de conta não suporta a transação |

## Reversal (cancelamento pós-desembolso)

| Status | Significado |
|---|---|
| `pending_fund` | Reversal iniciado, aguardando devolução pro fundo |
| `completed` | Reversal completo |
| `failed` | Reversal falhou (raro — investigação manual) |

## Parcelas (`installment.status_change`)

| Status | Significado |
|---|---|
| `opened` | Aberta, ainda não venceu |
| `waiting_payment` | Aberta, na data de vencimento |
| `paid` | Paga em dia |
| `paid_early` | Paga antes do vencimento |
| `paid_partial` | Paga parcialmente |
| `paid_overdue` | Paga após o vencimento |
| `paid_partial_overdue` | Paga parcialmente após o vencimento |
| `overdue` | Em atraso |
| `canceled` | Cancelada |

## Recuperar último estado

Pra consultar o estado atual de uma operação a qualquer momento:

```http
GET /debt/{DEBT_KEY}/collateral
```

Retorna `last_response` (último enumerador) + `reservation_status` + timestamp da última atualização.

---

# Margem Livre (Crédito Novo)

URL: /documentation/manual_exercito/margem-livre

Esteira de **originação direta** quando o militar tem margem consignável disponível e não está trazendo dívida externa nem refinanciando operação ativa. Cobre simulação e emissão para `reservation_type: new_credit`.

Para refinanciar uma operação QI ativa ou trazer dívida de outro banco, ver [Portabilidade + Refinanciamento](./04-portabilidade-refin.md).

## Pré-requisitos

- `balance_key` recebido na [Consulta de Margem](./02-consulta-margem.md), com webhook `military_payroll.balance.status_change` em `status: succeeded`.
- `balance` retornado > parcela desejada × prazo.
- `token` Zetra do militar disponível.

## 1. Simulação

Antes de emitir, simule as condições para validar margem, prazo e cronograma.

### Request

ENDPOINT /debt_simulation
MÉTODO POST

**Request Body**

```json
{
  "borrower": {
    "person_type": "natural",
    "individual_document_number": "45507529710"
  },
  "financial": {
    "first_due_date": "2026-07-01",
    "installment_face_value": 500.00,
    "disbursement_date": "2026-06-01",
    "number_of_installments": 24,
    "monthly_interest_rate": 0.0205,
    "interest_type": "pre_price_days",
    "credit_operation_type": "ccb",
    "interest_grace_period": 0,
    "principal_grace_period": 0,
    "fine_configuration": {
      "monthly_rate": 0.01,
      "interest_base": "calendar_days",
      "contract_fine_rate": 0.02
    }
  },
  "collaterals": [
    {
      "collateral_type": "military_payroll",
      "percentage": 1,
      "collateral_data": {
        "reservation_type": "new_credit",
        "registration_code": "146254221"
      }
    }
  ]
}
```

#### Campos chave

| Campo | Descrição |
|---|---|
| `collaterals[].collateral_type` | **`military_payroll`** (obrigatório) |
| `collaterals[].collateral_data.reservation_type` | **`new_credit`** — sempre pra margem livre |
| `collaterals[].collateral_data.registration_code` | Matrícula do militar |
| `financial.installment_face_value` | Parcela — ≤ `balance` retornado na consulta de margem |
| `financial.number_of_installments` | Prazo — ∈ `allowed_installment_numbers` |
| `financial.monthly_interest_rate` | Taxa mensal (ex: `0.0205` = 2,05% a.m.) |

`modality.code` **NÃO** é obrigatório em margem livre — só em refinanciamento.

### Response

Síncrona — retorna o cronograma completo (`disbursement_options[]` com parcelas, IOF, CET).

## 2. Emissão

Cria a CCB e dispara a esteira de averbação → formalização → desembolso.

### Request

ENDPOINT /debt
MÉTODO POST

**Request Body**

```json
{
  "borrower": {
    "name": "JOÃO DA SILVA",
    "email": "joao@email.com",
    "phone": { "number": "900000000", "area_code": "11", "country_code": "+55" },
    "address": {
      "city": "São Paulo", "state": "SP", "number": "215",
      "street": "Gilberto Sabino", "complement": "",
      "postal_code": "12345012", "neighborhood": "Pinheiros"
    },
    "role_type": "issuer",
    "birth_date": "1985-03-12",
    "mother_name": "MARIA DA SILVA",
    "person_type": "natural",
    "individual_document_number": "45507529710",
    "gender": "male",
    "nationality": "brasileiro",
    "is_pep": false,
    "marital_status": "single"
  },
  "financial": {
    "first_due_date": "2026-07-01",
    "installment_face_value": 500.00,
    "disbursement_date": "2026-06-01",
    "number_of_installments": 24,
    "monthly_interest_rate": 0.0205,
    "interest_type": "pre_price_days",
    "credit_operation_type": "ccb",
    "interest_grace_period": 0,
    "principal_grace_period": 0,
    "fine_configuration": {
      "monthly_rate": 0.01,
      "interest_base": "calendar_days",
      "contract_fine_rate": 0.02
    }
  },
  "simplified": true,
  "collaterals": [
    {
      "collateral_type": "military_payroll",
      "percentage": 1,
      "collateral_data": {
        "reservation_type": "new_credit",
        "reservation_method": "creation",
        "registration_code": "146254221",
        "token": "12345678"
      }
    }
  ],
  "disbursement_bank_account": {
    "name": "JOÃO DA SILVA",
    "bank_code": "104",
    "account_type": "checking_account",
    "account_digit": "1",
    "branch_number": "3880",
    "account_number": "000736703806",
    "document_number": "45507529710",
    "transfer_method": "pix"
  },
  "purchaser_document_number": "32402502000135"
}
```

#### `reservation_method` — quando a averbação dispara

**creation (averbação imediata)**

Averbação no Zetra dispara **junto com a criação do `/debt`**. Feedback rápido de margem antes da assinatura — ideal pra fluxos onde o operador quer saber logo se a margem reserva.

**issuing (averbação após formalização)**

Averbação só dispara **após a formalização** (`POST /debt/{KEY}/signed`). Usado quando a assinatura é coletada offline ou em fluxos onde o contrato chega já assinado.

#### Webhooks pós `/debt`

| Webhook | Status | Quando |
|---|---|---|
| `debt` | `waiting_signature` | Operação criada, aguardando assinatura |
| `credit_operation.collateral` | `successfully_accepted` → `successfully_reserved` | Averbação aceita pelo Zetra |
| `debt` | `disbursed` | Desembolso PIX/TED enviado |

→ Próximo passo: [Formalização](./05-formalizacao.md)

## Falhas comuns

| Webhook / Erro | Enumerador | Significado | Ação |
|---|---|---|---|
| Simulação | `INSUFFICIENT_MARGIN` | parcela × prazo > balance | Reduzir parcela ou prazo |
| Simulação | `INVALID_INSTALLMENT_NUMBER` | prazo fora de `allowed_installment_numbers` | Usar um dos prazos permitidos |
| `credit_operation.collateral` | `consignable_margin_exceeded` | margem insuficiente no momento da averbação (Zetra 359) | Reduzir parcela ou aguardar liberação |
| `credit_operation.collateral` | `military_blocked` | Militar com bloqueio em folha (Zetra 352) | Militar precisa resolver com Zetra |
| `credit_operation.collateral` | `communication_error` | Zetra indisponível (cod 241) | QI **retenta automaticamente** |

→ [Lista completa de enumeradores](./08-mapa-de-status.md)

## Sandbox

A sandbox militar **conecta na Zetra real de homologação** — não há whitelist local. Os exemplos de CPF/matrícula/token nesta página (`45507529710`, `146254221`, etc.) são apenas placeholders ilustrativos. Solicite ao time de Integrações QI Tech os dados reais cadastrados em `central_homologa.econsig.com.br`.

→ [Mocks (Sandbox)](./09-mocks-sandbox.md)

---

# Mocks (Sandbox)

URL: /documentation/manual_exercito/mocks-sandbox

:::caution Sandbox militar usa Zetra real de homologação
Ao contrário do SIAPE, o `military-payroll-api` em sandbox **NÃO usa mocks locais**. Em sandbox a integração aponta para o endpoint Host-a-Host de homologação da Zetra (eConsig):

- Sandbox: `https://www.econsig.com.br/central_homologa/services/HostaHostService-v8_0?wsdl`
- Produção: `https://api.econsig.com.br/central/services/HostaHostService`

Os dados de teste (CPFs, matrículas, tokens) são fornecidos **pela própria Zetra** via planilha de homologação oficial. **Suporte Zetra:** suporte@econsig.com.br.
:::

## Convênio QI Sociedade — Exército Brasileiro

| Item | Valor |
|---|---|
| **Cliente** | `QI_SOCIEDADE` |
| **Convênio** | `QI_SOCIEDADE-EB` |
| **Usuário API** | `qi_sociedade_xml` |
| **Senha API** | `qi12345` |
| **Código Serviço** | `001` |
| **Descrição Serviço** | `EMPRÉSTIMO` |
| **Código Verba** | `ZQD` |

## Servidores de Teste

Servidores fictícios cadastrados na Zetra homologação. Todos com **senha do servidor** = `abc123`.

### Cenário: Margem Negativa

Servidor sem margem disponível — toda tentativa de reserva retorna falha.

| # | Matrícula | CPF | Data Nascimento |
|---|---|---|---|
| 1 | `132722899` | `279.315.128-98` | 1983-04-01 |
| 2 | `143320397` | `213.628.178-05` | 1978-02-17 |

### Cenário: Margem Limite R$ 500,00

Margem reduzida — útil para testar limites e validação `INSUFFICIENT_MARGIN`.

| # | Matrícula | CPF | Data Nascimento |
|---|---|---|---|
| 3 | `346578694` | `432.108.069-00` | 1997-04-21 |
| 4 | `982435311` | `432.108.069-00` | 1993-03-20 |

> [!info]
> Matrículas 3 e 4 compartilham o mesmo CPF — útil para testar cenário "mesmo militar, múltiplas matrículas/órgãos".

### Cenário: Margem Limite R$ 10.000,00

Margem confortável — usar para testar fluxos completos de margem livre, refinanciamento e portabilidade.

| # | Matrícula | CPF | Data Nascimento |
|---|---|---|---|
| 5 | `346578694` | `540.770.447-15` | 1997-04-21 |
| 6 | `961683333` | `734.119.817-68` | 1963-04-09 |

### Cenário: BLOQUEADO

Servidor com bloqueio em folha — Zetra retorna `military_blocked` (código 352).

| # | Matrícula | CPF | Data Nascimento |
|---|---|---|---|
| 7 | `234674321` | `045.672.387-02` | 1975-01-01 |
| 8 | `342542124` | `472.635.472-87` | 1964-03-06 |

## Como mapear nos payloads QI

Quando construir o payload de `POST /military_payroll/balance`:

```json
{
  "document_number": "27931512898",
  "registration_code": "132722899",
  "authorization_document_key": "<document_key do POST /upload>",
  "token": "abc123"
}
```

- `document_number` — CPF sem máscara (remova `.` e `-` da tabela acima).
- `registration_code` — matrícula direto da tabela.
- `token` — senha do servidor (`abc123` para todos os testes).
- `authorization_document_key` — upload de qualquer PDF/PNG; em sandbox a Zetra não valida o conteúdo do termo.

## Webhook esperado por cenário

| Cenário | Webhook `military_payroll.balance.status_change` |
|---|---|
| Margem Negativa (1, 2) | `status: failed`, `failure_reason: invalid_balance` ou `consignable_margin_exceeded` |
| Margem Limite R$ 500 (3, 4) | `status: succeeded`, `balance: 500.00`, `allowed_installment_numbers: [...]` |
| Margem Limite R$ 10.000 (5, 6) | `status: succeeded`, `balance: 10000.00`, `allowed_installment_numbers: [...]` |
| BLOQUEADO (7, 8) | `status: failed`, `failure_reason: military_blocked` (Zetra 352) |
| CPF/matrícula fora da tabela | `status: failed`, `failure_reason: military_not_found` (Zetra 293) ou `invalid_registration_code` (Zetra 210) |

## Fluxo end-to-end recomendado

Para validar margem livre, use **teste 5** ou **teste 6** (margem alta):

1. `POST /upload` com PDF qualquer → `document_key`.
2. `POST /military_payroll/balance` com `27931512898` (margem negativa, pra testar failure) ou `54077044715` (margem 10k).
3. Aguardar webhook `military_payroll.balance.status_change`.
4. Em caso de sucesso, `POST /debt_simulation` com `installment_face_value` ≤ `balance` retornado.
5. `POST /debt` com `reservation_method: creation` (margem livre) ou `refinancing` (port/refin).
6. Aguardar webhook `credit_operation.collateral` (`successfully_accepted` → `successfully_reserved`).
7. `POST /debt/{KEY}/signed` com QI Sign ou data-signature opt-in.
8. Aguardar webhook `debt` (`disbursed`).
9. (opcional cancelamento) `PATCH /debt/{KEY}/cancel` dentro de 7 dias úteis → recebe PIX QR → simular pagamento → webhook `reversal`.

Para testar **portabilidade** com contrato externo, combine teste 5 ou 6 com um `original_contract_number` fictício (Zetra homologação aceita strings arbitrárias nesse campo durante port em sandbox).

## Códigos Zetra observados em sandbox

| Código | Mensagem | Mapeamento na QI |
|---|---|---|
| `000` | Operação realizada com sucesso | `succeeded` |
| `210` | Matrícula inválida | `invalid_registration_code` |
| `241` | Erro de comunicação | `communication_error` (QI retenta automaticamente) |
| `293` | Militar não encontrado | `military_not_found` |
| `352` | Militar bloqueado em folha | `military_blocked` |
| `359` | Margem consignável excedida | `consignable_margin_exceeded` |
| `360` | Margem disponível verificada | retorno de `consultarMargem` |

## Operação 24/7 em sandbox

A Zetra em homologação opera **24h/dia, todos os dias** — sem janela operacional restrita (mesmo comportamento da produção).

## Reset de reservas

Reservas Zetra em homologação **persistem indefinidamente** salvo cancelamento explícito. Limpe seu ambiente cancelando as reservas que não forem necessárias (`PATCH /debt/{KEY}/cancel`).

## Não há mocks locais ativos

O arquivo `src/connectors/zetra_mocker.py` no repo `military-payroll-api` existe mas **não é invocado** no fluxo de runtime — `EconsigConnector` chama diretamente o `ECONSIG_SERVICE_ADDRESS` configurado por ambiente. Se algum dia for necessário introduzir mocks locais (ex: Zetra fora do ar bloqueando QA), o `ZetraMocker` está disponível para ser ativado, mas hoje **toda integração de teste passa pela Zetra real de homologação**.

---

# Portabilidade + Refinanciamento

URL: /documentation/manual_exercito/portabilidade-refin

Fluxo de **compra de dívida de consignado militar** (Exército) via assinatura em lote. A QI Tech emite uma CCB de quitação (`debt_purchase`) que paga o banco vendedor, uma CCB de portabilidade (`portability`) que porta o contrato, e um `refinancing` consolidador **sempre obrigatório** que carrega seguro e troco. Tudo assinado uma única vez via QI Sign.

:::info Contas por operação
Cada operação do fluxo exige uma conta de desembolso distinta:

- **`debt_purchase`** → **conta interna QI** em nome do tomador. O desembolso cai nessa conta e quita a dívida origem no banco vendedor via `after_disbursement_actions` (boleto/PIX).
- **`refinancing`** → **conta externa do tomador**. O troco do refinanciamento é desembolsado nessa conta.

O parceiro abre a conta interna via `POST /account` antes da emissão. Ver [Conta Interna para Desembolso](./10-conta-interna-desembolso.md).
:::

## Cenários

O `refinancing` consolidador é **sempre obrigatório** no batch militar — é ele quem carrega seguro e troco.

| Cenário | Composição | Quando usar |
|---|---|---|
| **α** | 1× `debt_purchase` + 1× `portability` + 1× `refinancing` | Porta **uma** dívida externa |
| **β** | N× `debt_purchase` + N× `portability` + 1× `refinancing` | Porta **N dívidas** externas num único envelope |
| **γ** | α ou β + `financial.rebates` no `refinancing` | Qualquer composição acima com prêmio de seguro — gera `insurance_premium_term` automaticamente |

:::caution Regra do seguro e do troco
Seguro (`financial.rebates` com `fee_type: "insurance_premium_qi"`) e troco só podem ser enviados no `refinancing` consolidador (Passo 6).

- **`debt_purchase`** — `rebates` proibido (CCB de quitação não carrega seguro).
- **`portability`** — `rebates` proibido **e** `final_disbursement_amount` deve ser `0`.
:::

## Sequência de chamadas

```
0.  POST /debt_simulation  (opcional — condições do refinanciamento consolidado)

1.  POST /upload   (documentos do tomador)

2.  POST /account  (conta interna QI p/ debt_purchase)

3.  POST /document/document_batch      → criar envelope de assinatura

4.  POST /debt  (debt_purchase)        → desembolso em conta interna QI

5.  POST /debt  (portability)          → sem troco, sem seguro

6.  POST /debt  (refinancing)          → seguro + troco em conta externa

7.  PUT  /document/document_batch/{key}/send_to_signature
```

:::caution Ordem obrigatória de inserção no batch
`debt_purchase` deve ser inserido **antes** da `portability` que o referencia, e a `portability` **antes** do `refinancing` consolidador. Inverter a ordem dispara:

- **`DOC000110`** (HTTP 422) — `portability` cujo `refinanced_credit_operations[].operation_key` não casa com nenhum `debt_purchase` já inserido no batch.
- **`DOC000112`** (HTTP 422) — `refinancing` cujo `refinanced_credit_operations[].operation_key` não casa com nenhuma `portability` já inserida no batch.
:::

---

## 0. Simulação (opcional)

Antes de abrir o lote é possível simular as condições da operação consolidada — parcela, prazo, IOF, CET e troco — sem criar nada. A simulação é **uma só**, feita sobre o `refinancing` consolidador: as dívidas portadas entram como itens de `refinanced_credit_operations`. Não se simula `debt_purchase` nem `portability` separadamente.

ENDPOINT /debt_simulation
MÉTODO POST

:::info Como a dívida portada entra na simulação
Cada item de `refinanced_credit_operations` pode ser informado de duas formas:

- **Dívida externa** (ainda não existe na QI Tech) — informe `due_balance` com o saldo devedor do contrato no banco vendedor. Opcionalmente envie também `monthly_interest_rate` e `disbursement_date` da operação de origem: com esses dois campos a QI Tech **corrige o saldo** até a data de desembolso da nova operação; sem eles, o `due_balance` é usado exatamente como enviado.
- **Operação QI ativa** (refinanciamento puro) — informe `credit_operation_key`. O saldo devedor é calculado pela QI Tech.
:::

**Request Body**

**Dívida externa (port + refin)**

```json
{
  "borrower": {
    "person_type": "natural",
    "individual_document_number": "45507529710"
  },
  "financial": {
    "first_due_date": "2026-07-01",
    "installment_face_value": 500.00,
    "disbursement_date": "2026-06-01",
    "number_of_installments": 24,
    "monthly_interest_rate": 0.0185,
    "interest_type": "pre_price_days",
    "credit_operation_type": "ccb",
    "interest_grace_period": 0,
    "principal_grace_period": 0,
    "fine_configuration": {
      "monthly_rate": 0.01,
      "interest_base": "calendar_days",
      "contract_fine_rate": 0.02
    }
  },
  "collaterals": [
    {
      "collateral_type": "military_payroll",
      "percentage": 1,
      "collateral_data": {
        "reservation_type": "refinancing",
        "registration_code": "146254221"
      }
    }
  ],
  "refinanced_credit_operations": [
    {
      "due_balance": 8500.00,
      "monthly_interest_rate": 0.0225,
      "disbursement_date": "2024-03-15",
      "original_deadline": 60
    }
  ]
}
```

**Operação QI ativa (refin puro)**

```json
{
  "borrower": {
    "person_type": "natural",
    "individual_document_number": "45507529710"
  },
  "financial": {
    "first_due_date": "2026-07-01",
    "installment_face_value": 500.00,
    "disbursement_date": "2026-06-01",
    "number_of_installments": 24,
    "monthly_interest_rate": 0.0185,
    "interest_type": "pre_price_days",
    "credit_operation_type": "ccb",
    "interest_grace_period": 0,
    "principal_grace_period": 0,
    "fine_configuration": {
      "monthly_rate": 0.01,
      "interest_base": "calendar_days",
      "contract_fine_rate": 0.02
    }
  },
  "collaterals": [
    {
      "collateral_type": "military_payroll",
      "percentage": 1,
      "collateral_data": {
        "reservation_type": "refinancing",
        "registration_code": "146254221"
      }
    }
  ],
  "refinanced_credit_operations": [
    { "credit_operation_key": "<key da operação QI a refinanciar>" }
  ]
}
```

**Simulando pelo troco desejado**

```json
{
  "borrower": {
    "person_type": "natural",
    "individual_document_number": "45507529710"
  },
  "financial": {
    "first_due_date": "2026-07-01",
    "final_disbursement_amount": 2000.00,
    "disbursement_date": "2026-06-01",
    "number_of_installments": 24,
    "monthly_interest_rate": 0.0185,
    "interest_type": "pre_price_days",
    "credit_operation_type": "ccb",
    "interest_grace_period": 0,
    "principal_grace_period": 0,
    "fine_configuration": {
      "monthly_rate": 0.01,
      "interest_base": "calendar_days",
      "contract_fine_rate": 0.02
    }
  },
  "collaterals": [
    {
      "collateral_type": "military_payroll",
      "percentage": 1,
      "collateral_data": {
        "reservation_type": "refinancing",
        "registration_code": "146254221"
      }
    }
  ],
  "refinanced_credit_operations": [
    {
      "due_balance": 8500.00,
      "monthly_interest_rate": 0.0225,
      "disbursement_date": "2024-03-15"
    }
  ]
}
```

### Campos chave

| Campo | Descrição |
|---|---|
| `collaterals[].collateral_type` | **`military_payroll`** (obrigatório) |
| `collaterals[].collateral_data.reservation_type` | **`refinancing`** — a simulação representa o consolidador, mesmo quando há portabilidade de dívida externa |
| `collaterals[].collateral_data.registration_code` | Matrícula do militar no Zetra |
| `refinanced_credit_operations[].due_balance` | Saldo devedor da dívida portada. Obrigatório quando a dívida é **externa** (não existe `credit_operation_key`) |
| `refinanced_credit_operations[].monthly_interest_rate` | Taxa mensal do contrato de origem — usada, junto com `disbursement_date`, para corrigir o `due_balance` até o desembolso da nova operação |
| `refinanced_credit_operations[].disbursement_date` | Data de desembolso do contrato de origem |
| `refinanced_credit_operations[].original_deadline` | Prazo original do contrato de origem (informativo) |
| `refinanced_credit_operations[].credit_operation_key` | Chave da operação QI a refinanciar — alternativa ao `due_balance` |
| `financial.installment_face_value` | Parcela desejada — ≤ `balance` retornado na [Consulta de Margem](./02-consulta-margem.md) |
| `financial.final_disbursement_amount` | Troco desejado. Alternativa ao `installment_face_value`: o valor financiado vira `soma dos due_balance + troco` |
| `financial.number_of_installments` | Prazo — ∈ `allowed_installment_numbers` |

:::tip Cenário β (N dívidas portadas)
Para simular a portabilidade de **N** dívidas externas num único envelope, envie **N itens** em `refinanced_credit_operations`, cada um com seu `due_balance`. A simulação devolve as condições do consolidador que quita todas elas.
:::

:::note Diferenças em relação à emissão
- `modality.code` **não** é necessário na simulação — só na emissão (`POST /debt`) da `portability` e do `refinancing`.
- Não é preciso enviar `document_batch_key`, `disbursement_bank_account`, `purchaser_document_number` nem os dados cadastrais completos do tomador: na simulação o `borrower` se resume a `person_type` + `individual_document_number`.
- `portability_data` (com `origin_econsig_id` e `token`) também não entra na simulação — é exigido só na emissão da `portability`.
:::

### Response

Síncrona — retorna `disbursement_options[]` com cronograma de parcelas, IOF, CET e, quando há refinanciamento, o `due_balance` corrigido de cada dívida portada.

---

## 1. Upload dos documentos

Antes de abrir a conta e o lote, faça o **upload dos documentos** exigidos na operação via `POST /upload`. Cada chamada retorna um `document_key`, identificador do documento referenciado nas etapas seguintes.

ENDPOINT /upload
MÉTODO POST

→ Autenticação, headers, FormData e exemplos de código (Python / Node.js) em [Upload de Documentos](../upload_de_documentos/upload_de_documentos.md) .

:::caution Atenção
Salve o `document_key` retornado — ele é necessário para a consulta e o uso futuro do documento.
:::

---

## 2. Abrir a conta interna em nome do tomador

Em **compra de dívida**, **portabilidade** e **refinanciamento** do consignado militar (Exército), o desembolso da operação **não vai direto para a conta externa do tomador**: ele cai numa conta interna **em nome do tomador** (aberta pelo parceiro via `POST /account`). É a partir dessa conta que a QI executa as ações pós-desembolso — **quitação do contrato externo**, **repasse de troco**, **conciliação**.

ENDPOINT /account
MÉTODO POST

A conta é aberta pelo **parceiro** (autenticado com seus `client_integration_key`), com `account_owner.individual_document_number` apontando para o **CPF do militar tomador**. Reutilize a conta existente — uma por tomador (não abra uma nova a cada operação).

O campo `account_owner.document_identification` recebe o `document_key` retornado no **Passo 1** (upload do documento de identificação do tomador).

**Request Body**

```json
{
  "account_owner": {
    "person_type": "natural",
    "name": "JOÃO DA SILVA",
    "email": "joao@email.com",
    "individual_document_number": "<CPF DO MILITAR>",
    "mother_name": "MARIA DA SILVA",
    "birth_date": "1985-03-12",
    "is_pep": false,
    "document_identification": "<document_key DO PASSO 1>",
    "phone": {
      "country_code": "055",
      "area_code": "11",
      "number": "900000000"
    },
    "address": {
      "street": "Eixo Monumental",
      "state": "DF",
      "city": "Brasília",
      "neighborhood": "Asa Sul",
      "number": "215",
      "postal_code": "70000000"
    }
  }
}
```

### Campos chave

| Campo | Tipo | Descrição |
|---|---|---|
| `account_owner.person_type` | string | Fixo: **`natural`** (pessoa física) |
| `account_owner.individual_document_number` | string | **CPF do militar tomador** |
| `account_owner.document_identification` | string (UUID) | `document_key` do documento enviado no **Passo 1** |
| `account_owner.is_pep` | boolean | Indica se o tomador é pessoa politicamente exposta |

**Response Body**

```json
{
  "account_key": "1167955-...",
  "account_branch": "0001",
  "account_number": "1167955",
  "account_digit": "1",
  "owner_document_number": "<CPF DO MILITAR>",
  "owner_name": "<NOME DO MILITAR>",
  "bank_code": "329",
  "account_status": "active"
}
```

:::tip Idempotência por tomador
Se já existe conta ativa para esse `owner_document_number` no parceiro, evite chamar `POST /account` de novo — consulte `GET /accounts?owner_document_number= ` antes e reaproveite o `account_key` retornado.
:::

---

## 3. Abrir o lote

ENDPOINT /document/document_batch
MÉTODO POST

**Request Body**

```json
{
  "type": "military_payroll_external_batch",
  "certifier_type": "qi_sign",
  "batch_name": "Lote EB portabilidade - <UUID_UNICO>",
  "request_control_key": "<UUID_UNICO_2>"
}
```

### Campos chave

| Campo | Tipo | Descrição |
|---|---|---|
| `type` | string | Fixo: **`military_payroll_external_batch`** |
| `certifier_type` | string | Fixo: **`qi_sign`** |
| `batch_name` | string | Nome identificador do lote — **único** (não reutilize entre lotes) e **máximo 100 caracteres** |
| `request_control_key` | string (UUIDv4) | **Idempotência** — não reutilize entre lotes |

**Response Body**

```json
{
  "document_batch_key": "17f35e19-a039-468f-aaa7-84aa8edec3dc"
}
```

Guarde o `document_batch_key` retornado — ele é referenciado em todas as chamadas seguintes.

→ Para consultar, limpar documentos ou conferir o batch antes do envio, ver [Assinatura em Lote](./11-assinatura-em-lote.md).

---

## 4. Emitir `debt_purchase`

CCB de **quitação da dívida original**. A QI Tech vai pagar o banco vendedor.

ENDPOINT /debt
MÉTODO POST

:::info Particularidades do `debt_purchase`
- `document_batch_key` incluído na **raiz** do payload (mesmo nível de `borrower`, `financial`).
- `disbursement_bank_account` aponta para a **conta interna QI** do tomador (criada no Passo 2).
- `collaterals` vazio — o `debt_purchase` é a operação-ponte que carrega o saldo externo; **não** leva colateral.
- `after_disbursement_actions` na raiz define a quitação automática da dívida origem após o desembolso (boleto ou PIX do banco vendedor).
:::

**Request Body**

```json
{
  "borrower": {
    "name": "JOÃO DA SILVA",
    "email": "joao@email.com",
    "phone": { "number": "900000000", "area_code": "11", "country_code": "055" },
    "is_pep": false,
    "address": {
      "city": "Brasília",
      "state": "DF",
      "number": "215",
      "street": "Eixo Monumental",
      "complement": "",
      "postal_code": "70000000",
      "neighborhood": "Asa Sul"
    },
    "role_type": "issuer",
    "birth_date": "1985-03-12",
    "mother_name": "MARIA DA SILVA",
    "nationality": "Brasileiro",
    "person_type": "natural",
    "marital_status": "single",
    "individual_document_number": "45507529710",
    "gender": "male",
    "document_identification_type": "rg",
    "document_identification_number": "1234567",
    "document_identification_date": "2015-01-01"
  },
  "financial": {
    "first_due_date": "2026-07-01",
    "installment_face_value": 100,
    "disbursement_date": "2026-06-01",
    "limit_days_to_disburse": 5,
    "number_of_installments": 20,
    "monthly_interest_rate": 0.0185,
    "interest_type": "pre_price_days",
    "fine_configuration": {
      "monthly_rate": 0.01,
      "interest_base": "calendar_days",
      "contract_fine_rate": 0.02
    },
    "credit_operation_type": "ccb",
    "interest_grace_period": 0,
    "principal_grace_period": 0
  },
  "simplified": true,
  "collaterals": [],
  "requester_identifier_key": "<UUIDv4 gerado por request>",
  "disbursement_bank_account": {
    "bank_code": "329",
    "account_digit": "1",
    "branch_number": "0001",
    "account_number": "1167955",
    "document_number": "45507529710",
    "name": "JOÃO DA SILVA"
  },
  "purchaser_document_number": "<CNPJ do comprador>",
  "document_batch_key": "<document_batch_key DO PASSO 3>",
  "after_disbursement_actions": [
    {
      "action_type": "bankslip_payment",
      "action_data": {
        "qr_code": null,
        "destination": null,
        "digitable_line": "03399199530490000005237385601010297590005474921",
        "pix_transfer_type": null,
        "transaction_amount": 0
      }
    }
  ]
}
```

### Campos que devem ser alterados

| Campo | Obrigatório alterar? | Observação |
|---|---|---|
| `document_batch_key` | ✅ Sim | Valor retornado no Passo 3 |
| `borrower.*` | ✅ Sim | Dados reais do tomador |
| `financial.first_due_date` / `disbursement_date` | ✅ Sim | Conforme calendário da operação |
| `financial.installment_face_value` / `number_of_installments` / `monthly_interest_rate` | ✅ Sim | Conforme condições comerciais |
| `purchaser_document_number` | ✅ Sim | CNPJ do comprador (via variável de ambiente) |
| `requester_identifier_key` | ✅ Sim | UUIDv4 único por requisição |
| `disbursement_bank_account` | ✅ Sim | **Conta interna QI em nome do tomador** (Passo 2). O `account_branch` da resposta do `POST /account` vai no campo `branch_number` |
| `after_disbursement_actions` | ✅ Sim | Quitação da dívida origem. `action_type`: `bankslip_payment` (boleto) ou PIX. Preencha `digitable_line` (boleto) ou `qr_code` (PIX) do banco vendedor |

**Response Body**

```json
{
  "proposal_id": "<id interno>",
  "status": 200,
  "key": "<key da operação debt_purchase>",
  "data": {
    "credit_operation_key": "<mesmo valor de key>",
    "status": "waiting_signature"
  }
}
```

**Guarde a `key` retornada** — ela é passada em `refinanced_credit_operations[].operation_key` da `portability` correspondente.

---

## 5. Emitir `portability`

CCB de **portabilidade da dívida**. Cada portabilidade referencia **exatamente um** `debt_purchase` via `refinanced_credit_operations`. **Não carrega seguro nem troco** — ambos vão no `refinancing` consolidador.

ENDPOINT /debt
MÉTODO POST

:::info Particularidades da `portability`
- `collaterals[0].collateral_type` é **`military_payroll`** com `reservation_type: "portability"`.
- `collaterals[0].collateral_data.portability_data` é **obrigatório** — contém o `origin_econsig_id` (contrato de origem no Zetra) e o `token` do militar.
- `refinanced_credit_operations` carrega a `key` do `debt_purchase` correspondente.
- `modality.code` **`"0202"`** é obrigatório em portabilidade/refinanciamento do Exército.
:::

:::caution Portabilidade sem seguro e sem troco
Em batch militar, a `portability` **não pode** carregar `financial.rebates` (seguro). O seguro é enviado exclusivamente no `refinancing` consolidador. A QI Tech rejeita o `POST /debt` que violar essa regra.
:::

**Request Body**

```json
{
  "borrower": { "...": "mesmo borrower do Passo 4" },
  "financial": {
    "first_due_date": "2026-07-01",
    "disbursement_date": "2026-06-01",
    "limit_days_to_disburse": 5,
    "number_of_installments": 20,
    "monthly_interest_rate": 0.0185,
    "interest_type": "pre_price_days",
    "final_disbursement_amount": 0,
    "fine_configuration": {
      "monthly_rate": 0.01,
      "interest_base": "calendar_days",
      "contract_fine_rate": 0.02
    },
    "credit_operation_type": "ccb",
    "interest_grace_period": 0,
    "principal_grace_period": 0
  },
  "simplified": true,
  "collaterals": [
    {
      "percentage": 1,
      "collateral_type": "military_payroll",
      "collateral_data": {
        "reservation_type": "portability",
        "reservation_method": "issuing",
        "registration_code": "146254221",
        "token": "12345678",
        "portability_data": {
          "origin_econsig_id": "2016587",
          "token": "12345678"
        }
      }
    }
  ],
  "modality": { "code": "0202" },
  "requester_identifier_key": "<UUIDv4>",
  "disbursement_bank_account": { "...": "mesma conta interna do Passo 4" },
  "purchaser_document_number": "<CNPJ do comprador>",
  "document_batch_key": "<document_batch_key DO PASSO 3>",
  "refinanced_credit_operations": [
    { "operation_key": "<key DO PASSO 4>" }
  ]
}
```

### Campos que devem ser alterados

| Campo | Obrigatório alterar? | Observação |
|---|---|---|
| `document_batch_key` | ✅ Sim | Valor retornado no Passo 3 |
| `refinanced_credit_operations[0].operation_key` | ✅ Sim | `key` do `debt_purchase` referenciado (Passo 4) |
| `collaterals[0].collateral_data.registration_code` | ✅ Sim | Matrícula do militar no Zetra |
| `collaterals[0].collateral_data.token` | ✅ Sim | Token Zetra do militar |
| `collaterals[0].collateral_data.portability_data.origin_econsig_id` | ✅ Sim | ID do contrato de origem no Zetra (e-consignado da instituição vendedora) |
| `collaterals[0].collateral_data.portability_data.token` | ✅ Sim | Token Zetra do militar |
| `modality.code` | 🚫 Fixo | Sempre `"0202"` em portabilidade/refinanciamento do Exército |
| `financial.installment_face_value` | 🚫 Não enviar | Valor da parcela (auto calculado) |
| `financial.rebates` | 🚫 Proibido | Seguro não é aceito em portabilidade — só no `refinancing` |

**Response Body**

```json
{
  "proposal_id": "<id interno>",
  "status": 200,
  "key": "<key da operação portability>",
  "data": {
    "credit_operation_key": "<mesmo valor de key>",
    "status": "waiting_signature"
  }
}
```

**Guarde a `key` desta portabilidade** — usada em `refinanced_credit_operations` do `refinancing` consolidador (Passo 6).

### Erros possíveis na criação

| Código | HTTP | Quando |
|---|---|---|
| `DOC000110` | 422 | `refinanced_credit_operations[].operation_key` não casa com nenhum `credit_operation_key` de `debt_purchase` já inserido no batch |
| `DOC000114` | 422 | `refinanced_credit_operations[].operation_key` já está em outra portabilidade do mesmo batch (duplicidade) |
| `COP000515` | 400 | `final_disbursement_amount` ≠ `0` — portabilidade não carrega troco |
| `COP000516` | 400 | `financial.rebates` presente — portabilidade não aceita seguro |
| `INVALID_MODALITY_CODE` | 400 | portabilidade sem `modality.code: "0202"` |

---

## 6. Emitir `refinancing` consolidador

CCB **mãe** que consolida as portabilidades num único instrumento. **Sempre obrigatória** no batch militar — tanto no cenário α (1 portabilidade) quanto no β (N portabilidades). É a única operação do fluxo que carrega **seguro** e **troco**.

ENDPOINT /debt
MÉTODO POST

:::info Particularidades do `refinancing` consolidador
- `collaterals[0].collateral_type` é **`military_payroll`** com `reservation_type: "refinancing"`.
- `refinanced_credit_operations` lista as `key` de **todas** as portabilidades do batch.
- `disbursement_bank_account` aponta para a **conta externa do tomador** — destino do troco.
- `modality.code` **`"0202"`** é obrigatório.
- `financial.rebates` é **opcional** — único lugar do fluxo que aceita seguro.
- `after_disbursement_actions` só é enviado **quando há seguro** — liquida o prêmio após o desembolso.
:::

:::caution `after_disbursement_actions` exige seguro
`after_disbursement_actions` só pode ser enviado no `refinancing` **quando a operação tem seguro** (`financial.rebates` presente). Enviar `after_disbursement_actions` sem `rebates` faz a QI Tech rejeitar o `POST /debt`.
:::

**Request Body**

**Sem seguro**

```json
{
  "borrower": { "...": "mesmo borrower" },
  "financial": {
    "first_due_date": "2026-07-01",
    "installment_face_value": 1000,
    "disbursement_date": "2026-06-01",
    "limit_days_to_disburse": 5,
    "number_of_installments": 20,
    "monthly_interest_rate": 0.0185,
    "interest_type": "pre_price_days",
    "fine_configuration": {
      "monthly_rate": 0.01,
      "interest_base": "calendar_days",
      "contract_fine_rate": 0.02
    },
    "credit_operation_type": "ccb",
    "interest_grace_period": 0,
    "principal_grace_period": 0
  },
  "simplified": true,
  "collaterals": [
    {
      "percentage": 1,
      "collateral_type": "military_payroll",
      "collateral_data": {
        "reservation_type": "refinancing",
        "reservation_method": "issuing",
        "registration_code": "146254221",
        "token": "12345678"
      }
    }
  ],
  "modality": { "code": "0202" },
  "requester_identifier_key": "<UUIDv4>",
  "disbursement_bank_account": { "...": "conta externa do tomador" },
  "purchaser_document_number": "<CNPJ do comprador>",
  "document_batch_key": "<document_batch_key DO PASSO 3>",
  "refinanced_credit_operations": [
    { "operation_key": "<key da portabilidade 1>" },
    { "operation_key": "<key da portabilidade 2>" }
  ]
}
```

**Com seguro + troco (Cenário γ)**

```json
{
  "borrower": { "...": "mesmo borrower" },
  "financial": {
    "first_due_date": "2026-07-01",
    "installment_face_value": 1500,
    "disbursement_date": "2026-06-01",
    "limit_days_to_disburse": 5,
    "number_of_installments": 20,
    "monthly_interest_rate": 0.0185,
    "interest_type": "pre_price_days",
    "fine_configuration": {
      "monthly_rate": 0.01,
      "interest_base": "calendar_days",
      "contract_fine_rate": 0.02
    },
    "credit_operation_type": "ccb",
    "interest_grace_period": 0,
    "principal_grace_period": 0,
    "rebates": [
      {
        "fee_type": "insurance_premium_qi",
        "description": "credit_insurance_blindado"
      }
    ]
  },
  "simplified": true,
  "collaterals": [
    {
      "percentage": 1,
      "collateral_type": "military_payroll",
      "collateral_data": {
        "reservation_type": "refinancing",
        "reservation_method": "issuing",
        "registration_code": "146254221",
        "token": "12345678"
      }
    }
  ],
  "modality": { "code": "0202" },
  "requester_identifier_key": "<UUIDv4>",
  "disbursement_bank_account": { "...": "conta externa do tomador" },
  "purchaser_document_number": "<CNPJ do comprador>",
  "document_batch_key": "<document_batch_key DO PASSO 3>",
  "refinanced_credit_operations": [
    { "operation_key": "<key da portabilidade 1>" },
    { "operation_key": "<key da portabilidade 2>" }
  ],
  "after_disbursement_actions": [
    {
      "action_type": "bankslip_payment",
      "action_data": {
        "qr_code": null,
        "destination": null,
        "digitable_line": "03399199530490000005237385601010297590005474921",
        "pix_transfer_type": null,
        "transaction_amount": 0
      }
    }
  ]
}
```

### Campos que devem ser alterados

| Campo | Obrigatório alterar? | Observação |
|---|---|---|
| `document_batch_key` | ✅ Sim | Valor retornado no Passo 3 |
| `refinanced_credit_operations` | ✅ Sim | **Todas** as `key` das portabilidades emitidas no Passo 5 |
| `collaterals[0].collateral_data.registration_code` | ✅ Sim | Matrícula do militar no Zetra |
| `collaterals[0].collateral_data.token` | ✅ Sim | Token Zetra do militar |
| `reservation_method` | ✅ Sim | Sempre `"issuing"` para o consolidador |
| `modality.code` | 🚫 Fixo | Sempre `"0202"` |
| `disbursement_bank_account` | ✅ Sim | **Conta externa do tomador** — destino do troco |
| `financial.rebates` | ⚠️ Opcional | Único lugar do fluxo que aceita seguro. Incluir `[{ "fee_type": "insurance_premium_qi", ... }]` apenas se a operação tem seguro |
| `financial.final_disbursement_amount` | 🚫 Não enviar | Valor final do desembolso (troco) calculado automaticamente baseado no valor da parcela |
| `after_disbursement_actions` | ⚠️ Só com seguro | Liquida o prêmio do seguro após desembolso. **Só envie quando `rebates` está presente** — caso contrário a QI Tech rejeita o `POST /debt` |

### Erros possíveis na criação

| Código | HTTP | Quando |
|---|---|---|
| `DOC000109` | 422 | Batch já contém outro `refinancing` — só 1 por batch |
| `DOC000112` | 422 | `refinanced_credit_operations[].operation_key` não casa com nenhum `credit_operation_key` de portabilidade no batch |
| `COP000517` | 400 | `refinancing` **com** seguro (`rebates`) sem nenhuma `after_disbursement_actions` — seguro exige ao menos uma ação pós-desembolso |
| `COP000518` | 400 | `refinancing` **sem** seguro carregando `after_disbursement_actions` — só permitido quando há `rebates` |
| `INVALID_MODALITY_CODE` | 400 | refinanciamento sem `modality.code: "0202"` |

---

## 7. Enviar para assinatura

Fecha o lote e dispara os documentos para o QI Sign. **Antes desse PUT, nada é enviado ao militar.**

ENDPOINT /document/document_batch/DOCUMENT_BATCH_KEY/send_to_signature
MÉTODO PUT

Body: `{}`. Response: **HTTP 200**.

### Erros possíveis no envio

| Código | HTTP | Quando |
|---|---|---|
| `DOC000108` | 422 | Batch contém mais de 1 `insurance_premium_term` |
| `DOC000109` | 422 | Batch contém mais de 1 `refinancing` |
| `DOC000110` | 422 | `portability` cujo `refinanced_op` não casa com nenhum `debt_purchase` no batch |
| `DOC000111` | 422 | Batch **sem** `refinancing` consolidador |
| `DOC000114` | 422 | `debt_purchase` referenciado por 0 ou mais de 1 portabilidade |

:::tip Conferir antes de enviar
Use `GET /document/document_batch/DOCUMENT_BATCH_KEY` para listar os documentos agrupados e confirmar a composição antes do `send_to_signature`. Ver [Assinatura em Lote](./11-assinatura-em-lote.md).
:::

→ Próximo passo: [Formalização](./05-formalizacao.md)

---

## Mapa consolidado de erros

| Código | HTTP | Ponto de disparo | Quando |
|---|---|---|---|
| `DOC000108` | 422 | criação + envio | Mais de 1 `insurance_premium_term` no batch |
| `DOC000109` | 422 | criação + envio | Mais de 1 `refinancing` no batch |
| `DOC000110` | 422 | criação + envio | `portability` com `refinanced_op` sem `debt_purchase` casado no batch |
| `DOC000111` | 422 | envio | Batch sem `refinancing` consolidador |
| `DOC000112` | 422 | criação | `refinancing` com `refinanced_op` sem portabilidade casada no batch |
| `DOC000114` | 422 | criação + envio | `debt_purchase` referenciado por ≠ 1 portabilidade (0 órfão ou ≥ 2 duplicado) |
| `COP000515` | 400 | criação (`portability`) | `final_disbursement_amount` ≠ `0` na portabilidade |
| `COP000516` | 400 | criação (`portability`) | `financial.rebates` enviado na portabilidade |
| `COP000517` | 400 | criação (`refinancing`) | `refinancing` com seguro sem nenhuma `after_disbursement_actions` |
| `COP000518` | 400 | criação (`refinancing`) | `refinancing` sem seguro carregando `after_disbursement_actions` |
| `INVALID_MODALITY_CODE` | 400 | criação (`portability`/`refinancing`) | operação sem `modality.code: "0202"` |

:::info Notas sobre erros recorrentes
- `DOC000110` dispara em **dois momentos**: na criação da portabilidade (validação imediata) e no envio (cobertura defensiva).
- `DOC000114` dispara em **dois momentos**: na criação da segunda portabilidade duplicada e no envio (cobre o `debt_purchase` órfão, i.e. `count = 0`).
- `DOC000111` dispara **apenas no envio** — não há validação na criação.
- Batches que **não** são `military_payroll_external_batch` não disparam nenhuma das validações acima.
:::

---

## Glossário

| Termo | Significado |
|---|---|
| **CCB** | Cédula de Crédito Bancário — instrumento de dívida emitido pelo banco |
| **Zetra** | Sistema de gestão do e-consignado militar (Exército) — onde a reserva de margem é averbada |
| **matrícula militar** | `registration_code` — identificador do militar no Zetra |
| **token** | Token Zetra do militar — autoriza a operação de consignado (6 a 8 caracteres) |
| **portability_data** | Dados do contrato de origem no Zetra (`origin_econsig_id`, `token`) da instituição vendedora |
| **origin_econsig_id** | ID do e-consignado de origem no Zetra — o contrato externo que está sendo portado |
| **modality.code** | Código de modalidade do consignado militar — **`"0202"`** para portabilidade/refinanciamento |
| **credit_operation_key** | Chave única da operação retornada por `POST /debt` — também chamada `key` |
| **insurance_premium_term** | Documento extra gerado automaticamente no batch quando uma `portability` ou `refinancing` carrega `financial.rebates` com `fee_type: "insurance_premium_qi"`. **Nunca** originado de `debt_purchase` |
| **QI Sign** | Provedor de assinatura digital QI Tech (configurado via `certifier_type: "qi_sign"`) |

---

# Webhooks

URL: /documentation/manual_exercito/webhooks

Eventos assíncronos emitidos pela QI Tech durante o ciclo de vida da operação consignada militar. Todos seguem o protocolo unificado de [Webhooks QI](/documentation/webhooks/notificacoes_baas_e_laas) — 5 segundos pra resposta HTTP 200 com `encoded_body` assinado, 3 retries de 5 minutos em caso de falha.

:::danger Atenção!
Os webhooks da QI Tech **não devem ser mapeados de forma restrita**. Campos adicionais podem ser incluídos aos payloads a qualquer momento. Use desserialização permissiva.
:::

## Webhooks específicos do produto militar

| Webhook | Quando dispara | Origem |
|---|---|---|
| `military_payroll.balance.status_change` | Resultado da consulta de margem (`succeeded` ou `failed`) | military-payroll-api |
| `military_payroll.due_balance.status_change` | Saldo devedor (usado em refin/port) | military-payroll-api |
| `military_payroll.portability_contracts_report.status_change` | Relatório de contratos pra portabilidade | military-payroll-api |
| `credit_operation.collateral` | Averbação ou desaverbação no Zetra | credit-operation-api |

## Webhooks comuns LaaS

| Webhook | Status | Quando dispara |
|---|---|---|
| `debt` | `waiting_signature` | Operação criada, aguardando assinatura |
| `debt` | `signature_finished` | Assinatura concluída |
| `debt` | `disbursed` | Desembolso PIX/TED enviado |
| `debt` | `canceled` | Operação cancelada (ver `cancel_reason_enumerator`) |
| `debt` | `canceled_permanently` | Cancelamento definitivo |
| `debt` | `settled` | Operação liquidada (parcelas pagas) |
| `reversal` | `pending_fund` | Borrower pagou PIX QR de cancelamento — reversal iniciado |
| `credit_transfer.received_portability` | — | Portabilidade externa recebida (banco origem aceitou) |
| `credit_transfer_status_change` | — | Atualização do credit-transfer |
| `installment.status_change` | `paid` / `overdue` / etc | Mudança de status de parcela individual |
| `laas.devolution.refund_receipt` | `refunded` | Devolução de overpayment via PIX |

## Estrutura padrão do payload

Todos os webhooks LaaS seguem essa forma básica:

```json
{
  "key": "<UUID da operação>",
  "data": ,
  "status": "<status>",
  "webhook_type": "<tipo>",
  "event_datetime": "2026-06-01 14:30:00"
}
```

## Exemplos

### `military_payroll.balance.status_change` (sucesso)

```json
{
  "webhook_type": "military_payroll.balance.status_change",
  "key": "81da8afb-e1b2-4215-8093-c4b5feab8a9f",
  "status": "succeeded",
  "data": {
    "balance": 3500.00,
    "allowed_installment_numbers": [24, 36, 48, 60],
    "military_unit": "AMAN",
    "military_branch": "Sistema de Retribuição do Exterior",
    "category": "ATIVO",
    "name": "JOÃO DA SILVA",
    "document_number": "45507529710",
    "registration_code": "146254221",
    "birth_date": "1985-03-12",
    "grant_date": "2010-05-15"
  },
  "event_datetime": "2026-06-01 14:30:00"
}
```

### `credit_operation.collateral` (averbação reservada)

```json
{
  "webhook_type": "credit_operation.collateral",
  "key": "27a099df-4688-43cb-87fa-515b1cf343a5",
  "status": "success",
  "data": {
    "collateral_constituted": true,
    "enumerator": "successfully_reserved",
    "reservation_status": "reserved"
  },
  "event_datetime": "2026-06-01 15:00:00"
}
```

### `debt` (cancelado)

```json
{
  "webhook_type": "debt",
  "key": "27a099df-4688-43cb-87fa-515b1cf343a5",
  "status": "canceled",
  "data": {
    "cancel_reason": "Operação cancelada manualmente",
    "cancel_reason_enumerator": "manual"
  },
  "event_datetime": "2026-06-01 16:00:00"
}
```

### `reversal` (cancelamento pós-desembolso)

```json
{
  "webhook_type": "reversal",
  "credit_operation_key": "2893b8bd-8f4e-4e45-9325-fc7003beb869",
  "contract_number": "0000049333/TW",
  "reversal": {
    "status": "pending_fund",
    "amount": 2026.93,
    "amount_to_send": 2026.93,
    "is_total": true,
    "is_operation_canceled": true,
    "reversal_key": "eb0bbd1d-111d-4a61-bb65-c1f66a005ea2",
    "date": "2026-09-06"
  }
}
```

## Cancel reasons (`cancel_reason_enumerator`)

| Enumerador | Significado |
|---|---|
| `manual` | Cancelado via API ou portal |
| `waiting_signature` | Não assinou no prazo |
| `not_collateral_constituted` | Averbação falhou (consent_refused, consent_expired, etc.) |
| `is_portability` | Portabilidade falhou |
| `pix_max_retry` | Muitas falhas no desembolso PIX |
| `lack_of_resource` | Sem recurso pra desembolsar |
| `kyc_not_accepted` | KYC reprovado |
| `agencia_conta_invalida` | Erro em dados bancários do desembolso |
| `invalid_account` | Conta inválida |
| `rejected_payment` | Pagamento recusado pelo banco destino |

→ Lista completa em [Mapa de Status](./08-mapa-de-status.md)

## Reenvio Manual

Webhooks podem ser consultados e reenviados via portal seguindo [Reenvio de Webhooks](/documentation/notificacoes/reenvio_de_notificacoes).