# Flujo de pago — Casos límite

No todos los pagos siguen el [camino feliz](/es/docs/payment-flows/std-flow). Esta página cubre resultados no estándar — pago insuficiente, pago excesivo, expiración, transacciones on-chain fallidas y reembolsos — incluyendo qué hace Fluxis internamente, qué webhooks recibe y cómo manejar cada escenario en su integración.

## Descripción general

```mermaid
flowchart TD
    PR[Payment Request] --> Exp{Expired before payment?}
    Exp -->|Yes| E[expired]
    Exp -->|No| Pay{Customer pays}
    Pay --> Proc[processing]
    Proc --> Final{After finality}
    Final -->|Amount matches| Comp[completed → confirmed]
    Final -->|Too little| Under[underpaid]
    Final -->|Too much| Over[overpaid → confirmed]
    Final -->|Tx failed on-chain| Fail[stuck in processing]
```

| Scenario | Final status | Internal transaction | Webhook sent |
| -------- | ------------ | -------------------- | ------------ |
| Exact payment | `completed` → `confirmed` | Yes | `processing`, `completed` |
| Underpayment | `underpaid` | **No** | `processing`, `underpaid` |
| Overpayment | `overpaid` → `confirmed` | Yes (full received amount) | `processing`, `overpaid` |
| No payment in time | `expired` | No | No |
| On-chain tx reverts / fails | `processing` (stuck) | No | `processing` only |

## Matriz de entrega de webhooks

Fluxis envía webhooks a nivel de cuenta solo para estos cambios de estado de solicitud de pago:

| Status | Webhook delivered | Typical trigger |
| ------ | ----------------- | --------------- |
| `processing` | Yes | Cron detectó transferencia on-chain (salto 1) |
| `completed` | Yes | Confirmado tras finalidad; importe coincide (salto 2) |
| `underpaid` | Yes | Confirmado tras finalidad; importe demasiado bajo (salto 2) |
| `overpaid` | Yes | Confirmado tras finalidad; importe demasiado alto (salto 2) |
| `confirmed` | **No** | Transacción interna de ledger creada (salto 3) |
| `expired` | **No** | Cron de expiración marca la solicitud como expirada |
| `failed` | **No** | No establecido actualmente por el worker |
| `pending` / `created` | **No** | Creación inicial — consulte o use su propio estado de UI |

::::info
**Consulte estados sin webhooks**

Use `GET /v1/pos/{posID}/payment-request/{paymentRequestID}` para detectar estados `expired` y `confirmed`. Registre webhooks en `POST /v1/account/{accountID}/webhook` — consulte [Webhooks](/es/docs/developers/webhooks).
::::

---

## Underpaid

Un pago **underpaid** ocurre cuando el cliente envía menos del importe esperado y la transacción on-chain se confirma tras la finalidad.

### Qué hace Fluxis

```mermaid
sequenceDiagram
    participant W as Transaction Worker
    participant DB as Database
    participant WH as Webhook

    W->>W: Compare received vs expected
    Note over W: received < expected
    W->>DB: status → underpaid
    W->>WH: Webhook (underpaid)
    W->>W: Release vault
    Note over W: Hop 3 skipped — no internal transaction
```

1. El salto 2 compara `ReceivedAmount` (de la detección del cron) contra `ExpectedAmount`
2. El estado se establece en **`underpaid`**
3. Se envía un webhook con estado `underpaid`
4. Se libera el vault y se elimina de la caché Redis
5. **Se omite el salto 3** — no se crea registro interno de `Transaction`, el estado **no** alcanza `confirmed`

::::warning
**Sin transacción de ledger para underpaid**

Como el salto 3 solo se ejecuta para estados `completed` y `overpaid`, los pagos underpaid permanecen fuera del pipeline estándar de liquidación. Coordine la resolución con soporte Fluxis o inicie un [reembolso](#refunds-api) si devuelve fondos al cliente.
::::

### Manejo del comerciante

| Action | Recommendation |
| ------ | -------------- |
| **Do not fulfill** the order automatically | Trate `underpaid` como pago parcial que requiere revisión manual |
| **Contact the customer** | Solicite el saldo restante o acuerde un cumplimiento parcial |
| **Create a new payment request** | Para la diferencia pendiente, si el cliente acepta pagar más |
| **Request a refund** | Use la [Refunds API](#refunds-api) para devolver el importe parcial a la wallet del cliente |

Los estados elegibles para reembolso incluyen `underpaid`. Consulte [Refunds API](#refunds-api) abajo.

---

## Overpaid

Un pago **overpaid** ocurre cuando el cliente envía más del importe esperado.

### Qué hace Fluxis

```mermaid
sequenceDiagram
    participant W as Transaction Worker
    participant DB as Database
    participant WH as Webhook

    W->>W: Compare received vs expected
    Note over W: received > expected
    W->>DB: status → overpaid, save full received amount
    W->>WH: Webhook (overpaid)
    W->>W: Hop 3 — create internal transaction
    W->>DB: status → confirmed
```

1. El salto 2 establece el estado en **`overpaid`** y registra el importe recibido completo
2. Se envía un webhook con estado `overpaid`
3. El salto 3 crea una **Transaction** interna por el importe recibido completo
4. El estado transiciona a **`confirmed`** (sin webhook adicional)

### Manejo del comerciante

| Action | Recommendation |
| ------ | -------------- |
| **Fulfill the order** for the requested amount | El cliente pagó al menos el precio esperado |
| **Refund the excess** | Use `POST /v1/refunds/payment-request/{paymentRequestID}` con un `amount` explícito para la porción overpaid |
| **Contact support** | Para casos complejos donde el reembolso automático es insuficiente |

Cuando se omite `amount` en una solicitud de reembolso para un pago overpaid, Fluxis reembolsa por defecto la **porción overpaid** (recibido menos esperado).

---

## Expired

Una solicitud de pago **expira** cuando no se detecta pago on-chain antes del timestamp de expiración.

### Tiempos

| Setting | Value | Scope |
| ------- | ----- | ----- |
| Payment request expiration | **8 minutos** | Desde asignación de vault (estado `created`) |
| Payment intention expiration | **5 minutos** | Solo flujo PoS caja, antes de crear PR |
| Expiration check interval | Every **30 seconds** | Trabajo cron en segundo plano |

### Qué hace Fluxis

```mermaid
stateDiagram-v2
    created --> expired: expiration < now (cron)
    expired --> [*]
```

1. El cron de expiración encuentra solicitudes con `status = created` y `expiration < now`
2. Actualiza el estado a **`expired`**
3. **No se envía webhook** por expiración
4. El vault **no se libera inmediatamente** — se recicla cuando el pool de vaults lo reasigna (lógica de sobrescritura de vault expirado)

::::note
**Período de gracia para pagos tardíos**

Las transacciones transmitidas justo antes de la expiración aún pueden detectarse si la dirección vault permanece en caché Redis (TTL = expiración + 60 segundos). No asuma que `expired` significa que el cliente no puede pagar — compruebe webhooks `processing` tardíos o consulte el endpoint de estado.
::::

### Manejo del comerciante

| Action | Recommendation |
| ------ | -------------- |
| **Show expiration in UI** | Muestre una cuenta regresiva basada en el campo `expiration` de la respuesta de creación |
| **Create a new payment request** | Recuperación estándar — cada solicitud es de un solo uso |
| **Poll for late payments** | Si el cliente afirma haber pagado, compruebe el estado antes de crear una solicitud duplicada |

Consulte [Payment Requests — Timing](/es/docs/key-concepts/payment-request#timing-and-expiration) para detalles.

---

## Transacción fallida atascada en processing

Cuando una transacción on-chain **falla o revierte** tras ser detectada, el worker registra el fallo pero **no** actualiza el estado de la solicitud de pago.

### Qué hace Fluxis

En el salto 2 (`transaction_check_update_payment_request`), cuando `GetTransaction` devuelve estado **failed**:

1. El worker registra `"Blockchain Transaction Failed"`
2. Retorna sin actualizar la solicitud de pago
3. La solicitud de pago **permanece en `processing`** indefinidamente
4. No se envía webhook adicional más allá de la notificación inicial `processing`

```mermaid
flowchart LR
    A[processing] --> B{GetTransaction status}
    B -->|confirmed| C[completed / underpaid / overpaid]
    B -->|pending| D[Re-enqueue with finality delay]
    B -->|failed| E[Log only — stays processing]
```

::::warning
**Comportamiento conocido**

Este es el comportamiento actual de la plataforma. Si una solicitud está atascada en `processing` y la transacción on-chain ha fallado, contacte [support@fluxis.us](mailto:support@fluxis.us) para resolución manual. Consulte `GET /v1/pos/{posID}/payment-request/{paymentRequestID}` y verifique el hash de transacción en un explorador de bloques.
::::

### Manejo del comerciante

| Action | Recommendation |
| ------ | -------------- |
| **Verify on-chain** | Busque el hash de transacción (si está disponible) en un explorador de bloques |
| **Do not fulfill** | Un estado `processing` atascado no garantiza pago |
| **Contact support** | Proporcione el ID de solicitud de pago y hash de transacción |
| **Create a new payment request** | Si la transacción original falló definitivamente |

---

## Refunds API

Fluxis proporciona una Refunds API para iniciar reembolsos de solicitudes de pago elegibles. Los reembolsos se crean a nivel de API y activan una notificación webhook — **la ejecución on-chain del reembolso aún no está automatizada**.

### Estados elegibles

Los reembolsos pueden crearse cuando la solicitud de pago está en uno de:

- `completed`
- `confirmed`
- `overpaid`
- `underpaid`

### Crear un reembolso

```
POST /v1/refunds/payment-request/{paymentRequestID}
Authorization: Bearer <token>
x-fluxis-api-key: <api_key_id>
```

```json
{
  "refund_to_address": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb",
  "amount": "5.00",
  "reason": "Customer overpaid — returning excess"
}
```

| Field | Required | Description |
| ----- | -------- | ----------- |
| `refund_to_address` | Yes | Dirección wallet del cliente para recibir el reembolso |
| `amount` | No | Importe a reembolsar. Si se omite: importe completo para `completed`/`confirmed`, porción overpaid para `overpaid` |
| `reason` | No | Motivo en texto libre para auditoría |

Ejemplo de respuesta:

```json
{
  "status": "success",
  "data": {
    "id": "123e4567-e89b-12d3-a456-426614174000",
    "refund_to_address": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb",
    "amount": "5.00",
    "status": "processing"
  }
}
```

### Consultar estado del reembolso

```
GET /v1/refunds/{refundID}
```

### Webhook de reembolso

Al crear un reembolso, Fluxis envía un webhook con `notification_type: refund_status_update`:

```json
{
  "data": {
    "notification_type": "refund_status_update",
    "refund_request_id": "123e4567-e89b-12d3-a456-426614174000",
    "payment_request_id": "aa5d6c80-0b0b-4a2a-bbc8-14a41e6245bf",
    "status": "processing",
    "amount": "5.00"
  }
}
```

::::warning
**Ejecución on-chain pendiente**

La Refunds API crea un registro `processing` y envía un webhook. El procesamiento on-chain del reembolso está planificado pero aún no automatizado. Trate los registros de reembolso como intención hasta que `refund_transaction_hash` esté poblado en `GET /v1/refunds/{refundID}`.
::::

### Escenarios comunes de reembolso

| Scenario | Suggested approach |
| -------- | ------------------ |
| **Overpaid** | Omita `amount` para reembolsar el exceso, o especifique la porción overpaid exacta |
| **Underpaid — return partial payment** | Especifique `amount` igual al importe recibido (parcial) |
| **Completed — full refund** | Omita `amount` para reembolsar el pago completo |
| **Customer provided wrong address** | Contacte soporte si la dirección de reembolso necesita corrección tras el envío |

---

## Lista de verificación de integración para casos límite

Use esta lista al construir integraciones de producción:

```mermaid
flowchart TD
    A[Receive webhook] --> B{Verify HMAC signature}
    B -->|Invalid| X[Reject — 401]
    B -->|Valid| C{status?}
    C -->|processing| D[Show confirming UI — do not fulfill]
    C -->|completed| E[Fulfill order]
    C -->|underpaid| F[Manual review / refund / new PR]
    C -->|overpaid| G[Fulfill order / refund excess]
    H[Poll GET payment-request] --> I{status?}
    I -->|expired| J[Offer new payment request]
    I -->|processing + tx failed on-chain| K[Contact support]
```

1. **Maneje los cuatro estados webhook** — `processing`, `completed`, `underpaid`, `overpaid`
2. **Nunca cumpla en `processing`** — espere un resultado terminal de importe
3. **Consulte `expired` y `confirmed`** — estos no activan webhooks
4. **Muestre la cuenta regresiva de 8 minutos** — reduzca tickets de soporte por expiración
5. **Verifique firmas webhook** — consulte [Webhook Signature Verification](/es/docs/developers/webhook-signature-verification)
6. **Use la Refunds API** para resolución overpaid/underpaid cuando corresponda
7. **Monitoree `processing` atascado** — compruebe el explorador de bloques si el estado no progresa

## Documentación relacionada

- [Payment Flow — Happy Path](/es/docs/payment-flows/std-flow) — Flujo estándar crear → detectar → confirmar
- [Payment Requests](/es/docs/key-concepts/payment-request) — Definiciones de estado y ejemplos de API
- [Creating Payment Requests](/es/docs/merchant-integration/create-payreq) — Guía de integración
- [Webhooks](/es/docs/developers/webhooks) — Registro y formato de payload
- [Webhook Signature Verification](/es/docs/developers/webhook-signature-verification) — Verificación HMAC y flujo de prueba
- [FAQ — Payment Monitoring](/es/docs/faq#payment-monitoring) — Preguntas frecuentes
- [API Reference — Refunds](/api/refunds) — Documentación interactiva de endpoints
