> ## Documentation Index
> Fetch the complete documentation index at: https://firespark.cloud/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Pagos

> Proveedores, métodos, intents de pago, tenders, pagos mixtos y reapertura.

Fire spark mantiene un **catálogo global** de proveedores y métodos de pago. Un merchant activa un método creando un **pago** en el dashboard. Un pedido guarda cómo se paga como **intents de pago**. Cada intent es una lista de **tenders**. Los tenders son la fuente de verdad del método, el monto, el estado y dónde se cobra.

## El modelo

| Pieza | Qué es | De quién es |
| - | - | - |
| **Proveedor** | La empresa que mueve el dinero (`firespark`, `kushki`, `transbank`, …) | Catálogo de Fire spark |
| **Método de pago** | Lo que usa el cliente: `CASH`, `CARD`, `PIN_PAD`, `WALLET`, `BANK_TRANSFER`, `FINANCING` o `REDEMPTION` | Catálogo de Fire spark |
| **Pago** | La activación de un método por un merchant: credenciales, entorno, reglas y dónde aplica | Merchant |
| **Intent de pago** | Los tenders de un checkout, más totales y un snapshot de reglas | Pedido |
| **Tender** | La parte de ese checkout que cubre un método | Intent de pago |

Los tipos de método significan:

* `CASH`: lo cobra el personal en caja o en la puerta.
* `CARD`: tarjeta no presente (checkout web o app).
* `PIN_PAD`: tarjeta presente, en un terminal junto al kiosco o la caja.
* `WALLET`: QR o billeteras.
* `BANK_TRANSFER`: el cliente paga desde su banco y el canal lo verifica.
* `FINANCING`: compra ahora, paga después. Cubre una parte del pedido; el resto se paga con otro método.
* `REDEMPTION`: vales, recompensas o saldo. No es un método que el cliente elige en el checkout. Sale de un canje que nombra el pago `REDEMPTION` del merchant.

`REDEMPTION` no es un método real. Los métodos reales son todos los demás. `is_mixed` es verdadero cuando un intent tiene dos o más tenders reales. Un canje junto a una tarjeta no vuelve mixto el intent. `primary_tender_id` es el primer tender real. Es `null` solo cuando todos los tenders son `REDEMPTION`.

Un pedido tiene como máximo un intent `DRAFT` o `LOCKED`. Los intents anteriores se quedan en `payment_intents` como `COMPLETED` o `ABANDONED`.

## Dónde se cobra un tender

`collect_at` es `DEVICE`, `KIOSK`, `COUNTER`, `DOOR` u `OTHER`.

| Alcance | `collect_at` | Quién cobra |
| - | - | - |
| `digital` | `DEVICE`, y todo tender `REDEMPTION` | El canal, en el dispositivo |
| `in_person` | `COUNTER`, `KIOSK`, `DOOR`, `OTHER` | Una persona en la tienda o en la puerta |

Un nodo `PAYING` del fulfillment puede fijar `payment_scope` en `digital` o `in_person`. Sin alcance, el nodo espera todos los tenders vivos. El nodo avanza a `PAID` cuando cada tender de ese alcance está liquidado. Un alcance vacío queda pagado apenas el pedido entra. Un alcance solo de canjes queda pagado cuando esas recompensas ya están reservadas (`PENDING` con reserva cuenta como liquidado).

## Estados del intent

| Estado | Significado |
| - | - |
| `DRAFT` | Guardado en un carrito `OPEN`. Reemplázalo con [Guardar intent de pago](https://firespark.cloud/docs/es/storefront-api/orders/\[id]/payment-intent/put). |
| `LOCKED` | Congelado en [Colocar pedido](https://firespark.cloud/docs/es/storefront-api/orders/\[id]/place/post). El workflow cobra estos tenders. |
| `COMPLETED` | El estado de pago del intent bloqueado pasó a `PAID` o `REFUNDED`. |
| `ABANDONED` | Reemplazado antes de colocar, o dejado atrás cuando place armó un intent nuevo. |

## Estados del tender

También son el `payment_status` del pedido, derivado de los tenders vivos del intent activo.

| Estado | Significado |
| - | - |
| `IDLE` | Todavía no se cobró nada. El efectivo se queda aquí hasta que la tienda cobra. |
| `PENDING` | Esperando al proveedor o al cliente. |
| `PAID` | Aprobado. |
| `FAILED` | Rechazado o con error. El tender guarda el error. |
| `CANCELLED` | Anulado antes de liquidarse. |
| `REFUNDED` | Dinero devuelto después de liquidarse. Un reembolso parcial sigue en `PAID` y sube `refunded_total`. |

Derivación: sin tenders es `IDLE`. Cualquier `FAILED` es `FAILED`. Todos `CANCELLED` es `CANCELLED`. Todos `REFUNDED` o `CANCELLED` es `REFUNDED`. Todos liquidados es `PAID`. Todos `IDLE` es `IDLE`. Cualquier otro caso es `PENDING`.

Cada tender tiene un `attempt_reference`. Los reintentos usan uno nuevo. La misma referencia nunca crea un segundo cobro.

## Pagos mixtos y allocation

Envía los tenders antes de colocar. El servidor calcula el `amount` de cada tender y `allocation.amounts`. Tú envías `allocation` sin `amounts`.

`allocation` es `{ lines: [{ line_uid, units? }], fees: [line_uid] }` o `null`.

* Un solo tender real puede enviar `allocation: null`. Ese tender cubre lo que ningún otro cubre.
* Un tender `REDEMPTION` siempre envía `allocation: null`. Cubre un monto, no líneas.
* Con más de un tender real, un tender real sin allocation se rechaza (`PAYMENT_UNALLOCATED_LINES`).
* La propina y el delivery van solo en el tender real primario.
* Como máximo un tender es `CASH`.

## Canjes

Un canje es un vale, una recompensa o saldo. Todo canje necesita `payment_id` (un pago `REDEMPTION` activo del merchant) y `amount` (el dinero que cubre para toda la entrada, no por unidad). `quantity` es informativo. Un canje sin `payment_id` se rechaza con `REDEEM_PAYMENT_REQUIRED`.

El canje se muestra como descuento en su línea (`lines[].redeem`) o en el pedido (`redeem`), pero el dinero de la línea y del pedido no cambia: `group_total`, los impuestos y `totals.total` quedan completos. El tender `REDEMPTION` paga el monto canjeado y el método del cliente paga el resto.

`before_taxes` (por defecto `true`) limita el canje al valor antes de impuestos de su línea o pedido, así los impuestos quedan para el método del cliente. Con `before_taxes: false` el canje también puede cubrir los impuestos. Además, todo canje tiene tope en el total del pedido menos propina y delivery.

| Producto 10 + 15% de impuesto (total 11.50), canje de 10 o más | Tenders |
| - | - |
| `before_taxes: true` (por defecto) | `REDEMPTION` 10 y el método del cliente (por ejemplo `CASH`) 1.50 |
| `before_taxes: false` | Solo `REDEMPTION` 11.50 |

Los canjes que comparten un `payment_id` se vuelven un tender `REDEMPTION`. `details.rewards` lista cada recompensa. Cada recompensa tiene su `amount` con tope, y `details.amount` es la suma. El monto del tender es esa suma. Un tender que no coincide con los canjes agrupados es `PAYMENT_REDEMPTION_MISMATCH`.

Cada canje también tiene un paso en `redemption_steps`, en orden de aplicación: los canjes de líneas raíz en el orden de las líneas y luego los del pedido. Un paso lleva `payment_id`, `before_taxes`, `target` (`LINE` con `target_id`, u `ORDER`) y `discount_amount`, el `amount` con tope. `before` y `after` tienen `value` (lo que aún paga el método del cliente), `discount_amount` (lo cubierto hasta ahí) y `discount_rate` (cubierto / total); los pasos `LINE` también tienen `target_before` y `target_after`. Así, los pasos de un `payment_id` suman su tender `REDEMPTION` y los pasos de una línea suman el descuento que se muestra en ella. El servidor recalcula y guarda los pasos. Validate y place rechazan pasos del cliente con otros canjes u otro orden (`REDEMPTION_STEPS_MISMATCH`) o con otro dinero (`REDEMPTION_MISMATCH`). `redemptionSteps(order)` del SDK da los mismos pasos.

```json theme={null}
{
  "reward_id": "J9Y8PT9WVA",
  "reward_quantity": 1,
  "payment_id": "c32bc0b5-39bd-4448-88b1-a3ebbbb5dd3e",
  "before_taxes": true,
  "target": "LINE",
  "target_id": "11111111-1111-4111-8111-111111111111",
  "action": "UPDATE",
  "discount_amount": 10,
  "before": { "value": 11.5, "quantity": 1, "discount_amount": 0, "discount_rate": 0 },
  "after": { "value": 1.5, "quantity": 1, "discount_amount": 10, "discount_rate": 0.8695652173913043 },
  "target_before": { "value": 11.5, "quantity": 1, "discount_amount": 0, "discount_rate": 0 },
  "target_after": { "value": 1.5, "quantity": 1, "discount_amount": 10, "discount_rate": 0.8695652173913043 }
}
```

Un tender no lleva datos de descuento. Su `amount` es `{ currency, total }`: lo que paga ese tender. Un tender `REDEMPTION` solo agrega lo que necesitan la anulación y el reembolso: `payment_id` y `details` (`rewards[]` con `reward_id`, `quantity` y `amount`, más `details.amount`).

`services.payments.list` oculta los pagos `REDEMPTION`. Pasa `{ includeRedemptions: true }` cuando un flujo de canje los necesita. Esa bandera no es un query param: la API sigue devolviendo esos pagos y el SDK los filtra.

## Reapertura

[Reabrir pedido](https://firespark.cloud/docs/es/storefront-api/orders/\[id]/reopen/post) anula los tenders sin cobrar (los canjes reservados se liberan), cancela el origen como `VOIDED` y devuelve un pedido `OPEN` nuevo. El vínculo está en `metadata.reopen`: `{ as_order_id }` en el origen y `{ from_order_id }` en el nuevo. El pedido nuevo puede guardar los dos cuando se reabre otra vez. Un tender real vivo que ya está `PAID` o `REFUNDED` devuelve `400` `ORDER_PAYMENT_CAPTURED`. Un pedido ya `VOIDED` / `REVERSED` / `CANCELLED` (legacy) que nunca se cumplió se reabre tal cual cuando todos los tenders reales están `CANCELLED`, `FAILED` o `REFUNDED` completo (por ejemplo, tras una inyección fallida reversada en el dispositivo); ahí un tender `PAID` sigue siendo `400` y uno `IDLE` / `PENDING` es `422`. `order_id` es opcional y puede ser cualquier id que arme `genId` (`isGenId`: `[A-Za-z0-9-]`, una racha de al menos 8 `[0-9a-z]`, hasta 64 caracteres; `genOrderId` es una opción). Ejemplo: `BB2192100000001`. Un formato inválido es `400` `ORDER_ID_INVALID` y un id ocupado es `409` `ORDER_ID_EXISTS`. Si omites `order_id`, el comportamiento sigue igual. `REDEMPTION` no bloquea la reapertura. En un kiosco, el botón Cancelar durante la espera de liberación del checkout llama a este endpoint.

## Relacionado

> [card] [Métodos de pago soportados](https://firespark.cloud/docs/es/integrations/payments/index.md)
>
> Qué hay hoy y qué viene

> [card] [Usar pagos en el SDK](https://firespark.cloud/docs/es/guides/payments/use-payments-in-the-sdk.md)
>
> Instala un paquete y cobra un pedido

> [card] [Pedidos](https://firespark.cloud/docs/es/concepts/orders.md)
>
> A qué pertenece un intent de pago

> [card] [Errores de pago](https://firespark.cloud/docs/es/guides/payments/errors.md)
>
> Códigos del proveedor, reintentos y qué mostrar al cliente


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.