# 1 · Cotización y aceptación

Fase 1 del flujo. Felix le pide GTQ a Tesser (por Slack); Tesser le pide un
precio a Nexa, se lo muestra a Felix y lo bloquea cuando Felix dice que sí.
Ambas operaciones son <N /> **alojadas en Nexa, y Tesser las llama**.

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

    Note over T,N: Fase 1 · Cotización
    T->>N: POST /v1/quotes [N]
    N-->>T: 201 CREATED (precio, quoted_gtq, usdc_amount, expires_at)
    T->>N: POST /v1/quotes/{tesser_quote_id}/accept [N]
    N-->>T: 200 ACCEPTED (deposit_deadline)`}
/>

## Paso 1 · Crear la cotización <N />

**Operación:** [`POST /v1/quotes`: Crear cotización (op 1)](/api-nexa/quotes#create-quote-op-1)
· alojada por **Nexa**, llamada por **Tesser**.

Tesser genera el `tesser_quote_id` (UUIDv4) *antes* de la llamada. Es a la vez
el identificador que usan todas las llamadas y webhooks posteriores, y la
clave de idempotencia. La solicitud lleva el cliente (`FELIX` al momento del
lanzamiento) y `desired_gtq`, el GTQ con el que Felix quiere quedarse.

Nexa responde con el precio y con `usdc_amount`, **el USDC que Felix debe
entregar**, calculado como `quoted_gtq / usdc_gtq_price` y redondeado **hacia
arriba** a 6 decimales, de modo que entregar exactamente `usdc_amount` siempre
alcance para cubrir `quoted_gtq`. Tesser repite ese número y nunca lo deriva
por su cuenta: con dos calculadoras, ambas partes pueden discrepar en el sexto
decimal.

- `quoted_gtq` puede ser **menor que** `desired_gtq`. Eso es una ejecución
  parcial por liquidez limitada. Aceptar significa aceptar `quoted_gtq`; el
  resto es una cotización nueva.
- `expires_at` es el plazo de aceptación. Las cotizaciones no aceptadas
  expiran **en silencio**: no hay webhook de expiración. Tesser conoce
  `expires_at` y aplica su propio tiempo de espera localmente.
- Reintentar con el mismo `tesser_quote_id` y un cuerpo equivalente devuelve
  `201` con el estado **actual** de la cotización. El mismo ID con un cuerpo
  distinto da `409 QUOTE_CONFLICT`.

Qué tan amplia puede ser la ventana que ofrece Nexa, y si es fija o depende de
la liquidez, es la [pregunta abierta 1](/es/open-questions).

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

**Qué puede salir mal: crear cotización**

| `error_code` | HTTP | Cuándo |
| --- | --- | --- |
| `VALIDATION_ERROR` | 400 | Monto mal formado, `customer` desconocido, UUID inválido. |
| `UNAUTHENTICATED` | 401 | Falta el certificado de cliente o la clave de API del cliente, o son inválidos. |
| `QUOTE_CONFLICT` | 409 | Mismo `tesser_quote_id`, cuerpo distinto. |
| `NO_LIQUIDITY` | 422 | Nexa no puede cotizar ningún monto en este momento. |
| `INTERNAL_ERROR` | 500 | Falla inesperada del lado de Nexa. |

</div>

## Paso 2 · Aceptar la cotización <N />

**Operación:** [`POST /v1/quotes/{tesser_quote_id}/accept`: Aceptar cotización (op 2)](/api-nexa/quotes#accept-quote-op-2)
· alojada por **Nexa**, llamada por **Tesser**.

El cuerpo va vacío (`{}`): la ruta identifica la cotización, y la aceptación
es, por definición, de `quoted_gtq`. Aceptar bloquea el tipo de cambio e
inicia el reloj de `deposit_deadline`.

- `deposit_deadline` indica cuánto tiempo mantiene Nexa el tipo de cambio
  bloqueado mientras espera el **primer** reporte de depósito. Pasado el plazo
  sin que se reporte nada, la cotización queda `EXPIRED` y las llamadas
  posteriores reciben `409 QUOTE_EXPIRED`.
- Volver a aceptar una cotización que ya está en `ACCEPTED` (o en un estado
  posterior) devuelve `200` con el objeto actual de la cotización. Es
  idempotente, no un error, así que un reintento tras un corte de red nunca
  puede fallar en falso.
- Un `tesser_quote_id` desconocido da `404 QUOTE_NOT_FOUND`.

La duración del plazo, y si una solicitud de fondos adicionales lo extiende,
es la [pregunta abierta 2](/es/open-questions).

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

**Qué puede salir mal: aceptar cotización**

| `error_code` | HTTP | Cuándo |
| --- | --- | --- |
| `VALIDATION_ERROR` | 400 | Parámetro de ruta o cuerpo mal formado. |
| `UNAUTHENTICATED` | 401 | Falta el certificado de cliente o la clave de API del cliente, o son inválidos. |
| `QUOTE_NOT_FOUND` | 404 | No existe ninguna cotización con este `tesser_quote_id`. |
| `QUOTE_EXPIRED` | 409 | `expires_at` venció antes de la aceptación. |
| `INTERNAL_ERROR` | 500 | Falla inesperada del lado de Nexa. |

</div>

## Recuperar el estado

Si Tesser pierde el rastro de una cotización, la operación opcional
[`GET /v1/quotes/{tesser_quote_id}`](/api-nexa/quotes#get-quote-optional-op-8)
<N /> responde en una sola llamada a la pregunta "¿en qué estado considera
*Nexa* que está?".

**Siguiente:** [2 · Reporte de depósito](/es/flow-nexa/deposit-reporting).
