# 3 · Decisión de acreditación

Fase 3 del flujo, y la única totalmente asíncrona. Nexa tiene un reporte de
depósito; Nexa decide. La decisión llega a Tesser como un webhook entregado
al <T /> **receptor de Tesser, que Nexa invoca**:
[`POST /v1/webhooks/nexa/{organizationId}`: Recibir webhook de Nexa (op 4)](/api-tesser/webhooks#receive-nexa-webhook-op-4).

<Mermaid
  chart={`sequenceDiagram
    autonumber
    participant T as Tesser (orquestador)
    participant N as Banco Nexa

    Note over T,N: Fase 3 · Decisión de acreditación de Nexa (asíncrona)
    alt Nexa acredita
        N->>T: webhook quote.credit.sent [T]
        N->>T: webhook quote.credit.confirmed (gtq_amount definitivo) [T]
    else Nexa solicita más fondos
        N->>T: webhook quote.additional_funds_requested [T]
        T->>N: POST .../deposits (otro reporte) [N]
    else Nexa rechaza
        N->>T: webhook quote.rejected [T]
    end`}
/>

## Paso 4a · Nexa acredita, con `quote.credit.sent` y luego `quote.credit.confirmed` <T />

**Operación:** [`POST /v1/webhooks/nexa/{organizationId}`: Recibir webhook de Nexa (op 4)](/api-tesser/webhooks#receive-nexa-webhook-op-4)
· lo aloja **Tesser**, lo llama **Nexa**.

Dos eventos, en ese orden:

| `event_type` | Significado | `data` |
| --- | --- | --- |
| `quote.credit.sent` | Nexa decidió acreditar; la instrucción ya se envió al core bancario. | `tesser_quote_id`, `quote_status: "CREDIT_SENT"`, `gtq_amount` |
| `quote.credit.confirmed` | Los GTQ están disponibles en la cuenta de Felix en Nexa. | `tesser_quote_id`, `quote_status: "CREDIT_CONFIRMED"`, `gtq_amount` (**definitivo**, y puede diferir de `quoted_gtq` según la decisión de Nexa), `credited_at` |

El `gtq_amount` de `quote.credit.confirmed` es la cifra que Tesser toma como
verdadera y la que debe devolver al
[crear el pago](/api-nexa/payments#create-payment-op-5), donde Nexa la
contrasta.

Qué significan `credit.sent` y `credit.confirmed` dentro del core bancario de
Nexa, y cuánto tiempo se espera entre uno y otro, es la
[pregunta abierta 2](/es/open-questions).

## Paso 4b · Nexa solicita más fondos, con `quote.additional_funds_requested` <T />

**Operación:** [`POST /v1/webhooks/nexa/{organizationId}`: Recibir webhook de Nexa (op 4)](/api-tesser/webhooks#receive-nexa-webhook-op-4)
· lo aloja **Tesser**, lo llama **Nexa**.

| `event_type` | Significado | `data` |
| --- | --- | --- |
| `quote.additional_funds_requested` | Nexa quiere más USDC antes de acreditar. | `tesser_quote_id`, `quote_status: "DEPOSIT_REPORTED"`, `usdc_total_reported`, `usdc_additional_requested`, `note` (texto libre) |

**Este evento no cambia el estado.** La cotización permanece en
`DEPOSIT_REPORTED` y acumula más reportes mientras la decisión de Nexa sigue
pendiente. La respuesta de Tesser es otro
[reporte de depósito](/api-nexa/deposits#report-usdc-deposit-op-3) <N /> en
cuanto llega el USDC adicional.

Como el evento transmite una acción y no un avance de estado, Tesser lo
procesa en la **primera entrega de su `event_id`**, sin importar la regla de
alcanzabilidad. Véase la [guía de webhooks](/es/webhooks-guide).

Si `usdc_additional_requested` es vinculante o apenas indicativo, y si Nexa
puede cancelar la solicitud y acreditar de todos modos, es la
[pregunta abierta 9](/es/open-questions).

## Paso 4c · Nexa rechaza, con `quote.rejected` <T />

**Operación:** [`POST /v1/webhooks/nexa/{organizationId}`: Recibir webhook de Nexa (op 4)](/api-tesser/webhooks#receive-nexa-webhook-op-4)
· lo aloja **Tesser**, lo llama **Nexa**.

| `event_type` | Significado | `data` |
| --- | --- | --- |
| `quote.rejected` | Nexa se niega a acreditar. | `tesser_quote_id`, `quote_status: "REJECTED"`, `reason_code` (`RISK`, `AMOUNT` u `OTHER`), `note` |

`REJECTED` es un estado terminal. La vía de recuperación es una cotización
nueva, y a partir de ese momento el endpoint de depósitos devuelve
`409 QUOTE_REJECTED`. El USDC ya se movió en cadena, y lo que ocurra con él
es un asunto operativo y fuera de banda para el POC
([pregunta abierta 4](/es/open-questions)).

Las reglas de decisión de Nexa (acreditar lo cotizado, acreditar a prorrata,
solicitar más fondos o rechazar) y el SLA entre el reporte de depósito y el
evento de decisión son la [pregunta abierta 3](/es/open-questions).

<div className="what-can-go-wrong">

**Qué puede salir mal: entrega de webhooks**

| `error_code` | HTTP | Cuándo |
| --- | --- | --- |
| `VALIDATION_ERROR` | 400 | Envoltorio mal formado, `event_type` desconocido, `data` inválido para ese tipo de evento. |
| `UNAUTHENTICATED` | 401 | No hay certificado de cliente, la huella digital no se reconoce, o la identidad resuelta por mTLS no coincide con el `{organizationId}` de la ruta. |
| `INTERNAL_ERROR` | 500 | Falla inesperada del lado de Tesser. **Este sí conviene reintentarlo.** |

Modos de falla operativos que *no* son errores:

- **Entrega duplicada.** Al menos una vez significa que los duplicados son
  esperables. Tesser deduplica por `event_id` y aun así responde 2xx.
- **Entrega fuera de orden.** Un evento obsoleto (el estado actual o uno
  anterior) se confirma y no cambia nada.
- **Evento en conflicto**, por ejemplo `PAYMENT_FAILED` después de
  `PAYMENT_COMPLETED`, o `quote.credit.sent` después de `quote.rejected`.
  Tesser responde `200` **y levanta una alerta de operaciones**: eso es un
  incidente de integridad de datos entre las dos empresas, no un
  reordenamiento, e ignorarlo en silencio ocultaría una divergencia de dinero
  real.
- **Ninguna decisión.** En el POC no hay tiempo límite del lado de Nexa en
  esta fase. Una cotización que ya tiene un depósito reportado nunca expira
  de forma automática; si la decisión no llega, se resuelve entre los equipos
  de operaciones.

</div>

**Siguiente:** [4 · Desembolso en GTQ](/es/flow-nexa/gtq-payout).
