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

# Caja

> Apertura, movimientos, cierre con arqueo y consulta de cortes de caja

| Permiso | Endpoints |
| - | - |
| `cash_register` | `GET /cash-registers`, `GET /cash-registers/current`, `GET /cash-registers/{id}` |
| `cash_register.operate` | `POST /cash-registers/open`, `POST /cash-registers/{id}/movements`, `POST /cash-registers/{id}/close` |

<Note>
  Son permisos **explícitos**: deben marcarse uno por uno en **Integraciones externas**; las integraciones existentes no los reciben automáticamente.
</Note>

Para puntos de venta de terceros: abre la caja de una sucursal, registra ingresos y gastos, y ciérrala con arqueo. Usa la misma lógica que **Caja** en FileXpress, así que los cortes se ven igual en la web.

* Cada sucursal tiene **una sola caja abierta** a la vez (por ambiente del negocio).
* Toda caja pertenece a un **cajero**: un usuario de FileXpress con acceso a la sucursal. Así los cortes siguen saliendo por cajero.
* Las acciones hechas por la API quedan registradas como `API: {nombre de la integración}` (en `opened_by` y `closed_by`).

## Cortes de caja

```http theme={null}
GET /cash-registers?branch_id={branch_id}&status=closed&start_date=2026-10-01&end_date=2026-10-06
```

| Parámetro | Tipo | Requerido | Descripción |
| - | - | - | - |
| `branch_id` | string | Sí | Sucursal. |
| `status` | string | No | `open` o `closed`. |
| `start_date` | date | No | Fecha de apertura desde (`YYYY-MM-DD`). |
| `end_date` | date | No | Fecha de apertura hasta; no anterior a `start_date`. |
| `per_page` | integer | No | 1 a 200. Por defecto 50. |

```bash theme={null}
curl "https://api.filexpress.app/api/external/cash-registers?branch_id=9d1c5a3e-...&status=closed" \
  -H "X-API-Key: fx_xxxxxxxx"
```

```json theme={null}
{
  "status": true,
  "data": {
    "data": [
      {
        "id": "4e81...",
        "branch_id": "9d1c5a3e-...",
        "status": "closed",
        "cashier": { "id": "1b7f...", "name": "Ana López" },
        "opening_date": "2026-10-05T08:00:12-06:00",
        "closing_date": "2026-10-05T18:02:40-06:00",
        "opening_amount": 100.0,
        "declared_amount": 845.5,
        "difference_amount": -0.5,
        "total_sales": 1520.75,
        "total_cash_sales": 766.0,
        "total_card_sales": 690.75,
        "total_other_sales": 64.0,
        "total_expenses": 25.0,
        "total_other_incomes": 5.0,
        "notes": "Cierre sin novedad",
        "opened_by": "API: POS Sucursal Centro",
        "closed_by": "API: POS Sucursal Centro"
      }
    ],
    "pagination": { "current_page": 1, "last_page": 1, "per_page": 50, "total": 1 }
  }
}
```

| Campo | Descripción |
| - | - |
| `cashier` | Usuario de FileXpress que opera la caja. |
| `difference_amount` | Monto declarado − efectivo esperado (negativo = faltante). |
| `total_cash_sales` / `total_card_sales` / `total_other_sales` | Ventas por forma de pago: código `01` (efectivo), `02`/`03` (tarjeta débito/crédito) y el resto. |
| `total_other_incomes` / `total_expenses` | Movimientos de ingreso y gasto de la caja. |
| `closed_by` | `null` mientras la caja está abierta. |

Los totales del cierre se guardan al cerrar; en una caja abierta usa el `summary` en vivo. Ordenado de la apertura más reciente a la más antigua. **Errores**: `404` `Branch not found`; `422` validación.

## Caja abierta

```http theme={null}
GET /cash-registers/current?branch_id={branch_id}
```

Devuelve la caja abierta de la sucursal con su resumen en vivo, o `data: null` si no hay ninguna.

```json theme={null}
{
  "status": true,
  "data": {
    "id": "4e93...",
    "branch_id": "9d1c5a3e-...",
    "status": "open",
    "cashier": { "id": "1b7f...", "name": "Ana López" },
    "opening_date": "2026-10-06T08:01:05-06:00",
    "closing_date": null,
    "opening_amount": 100.0,
    "declared_amount": null,
    "difference_amount": null,
    "total_sales": null,
    "total_cash_sales": null,
    "total_card_sales": null,
    "total_other_sales": null,
    "total_expenses": null,
    "total_other_incomes": null,
    "notes": null,
    "opened_by": "API: POS Sucursal Centro",
    "closed_by": null,
    "summary": {
      "total_sales": 412.3,
      "total_cash": 210.0,
      "total_card": 180.3,
      "total_other": 22.0,
      "total_expenses": 15.0,
      "more_income": 0.0,
      "sales_count": 18,
      "cash_movements": 1,
      "expected_cash": 295.0
    }
  }
}
```

| Campo | Descripción |
| - | - |
| `summary.expected_cash` | Efectivo esperado = monto inicial + ventas en efectivo + otros ingresos − gastos. |
| `summary.sales_count` | Ventas procesadas de la caja: las vinculadas a ella o, sin caja asignada, las emitidas en la sucursal entre la apertura y el cierre (o ahora). |
| `summary.cash_movements` | Cantidad de movimientos de ingreso/gasto. |

**Errores**: `404` `Branch not found`.

## Detalle de un corte

```http theme={null}
GET /cash-registers/{id}
```

Devuelve la caja (mismos campos que el listado), su `summary` y sus `movements` en orden de registro:

```json theme={null}
{
  "status": true,
  "data": {
    "id": "4e81...",
    "status": "closed",
    "...": "...",
    "summary": { "total_sales": 1520.75, "expected_cash": 846.0, "...": "..." },
    "movements": [
      {
        "id": "a310...",
        "type": "expense",
        "amount": 25.0,
        "description": "Compra de bolsas",
        "reference": "REC-221",
        "sale_id": null,
        "created_by": "API: POS Sucursal Centro",
        "created_at": "2026-10-05T12:30:00-06:00"
      }
    ]
  }
}
```

**Errores**: `404` `Cash register not found` (inexistente o de otro negocio).

## Abrir caja

```http theme={null}
POST /cash-registers/open
```

| Campo | Tipo | Requerido | Descripción |
| - | - | - | - |
| `branch_id` | string | Sí | Sucursal. |
| `user_id` | string | Sí | Cajero: usuario de FileXpress asignado a la sucursal o a la empresa. |
| `opening_amount` | number | Sí | Monto inicial en efectivo (mayor o igual a 0). |
| `notes` | string | No | Máx. 500. |

```bash theme={null}
curl -X POST https://api.filexpress.app/api/external/cash-registers/open \
  -H "X-API-Key: fx_xxxxxxxx" \
  -H "Idempotency-Key: apertura-centro-20261006" \
  -H "Content-Type: application/json" \
  -d '{"branch_id":"9d1c5a3e-...","user_id":"1b7f...","opening_amount":100.00}'
```

**Respuesta `201`**: la caja con `status: "open"` (mismos campos que el listado, sin `summary`).

**Errores**

| Código | Causa |
| - | - |
| `404` | `Branch not found`. |
| `409` | `There is already an open cash register for this branch.` |
| `422` | `The user does not exist or has no access to this branch.` / validación. |

## Registrar ingreso o gasto

```http theme={null}
POST /cash-registers/{id}/movements
```

| Campo | Tipo | Requerido | Descripción |
| - | - | - | - |
| `type` | string | Sí | `income` (ingreso) o `expense` (gasto). |
| `amount` | number | Sí | Mínimo 0.01. |
| `description` | string | Sí | Máx. 255. |
| `reference` | string | No | Máx. 100. |

```bash theme={null}
curl -X POST https://api.filexpress.app/api/external/cash-registers/4e93.../movements \
  -H "X-API-Key: fx_xxxxxxxx" \
  -H "Idempotency-Key: gasto-centro-20261006-001" \
  -H "Content-Type: application/json" \
  -d '{"type":"expense","amount":15.00,"description":"Compra de bolsas","reference":"REC-230"}'
```

**Respuesta `201`**

```json theme={null}
{
  "status": true,
  "data": {
    "id": "a322...",
    "type": "expense",
    "amount": 15.0,
    "description": "Compra de bolsas",
    "reference": "REC-230",
    "summary": { "total_sales": 412.3, "expected_cash": 295.0, "...": "..." }
  }
}
```

**Errores**: `404` `Cash register not found`; `409` `Cash register is not open.`; `422` validación.

## Cerrar caja

```http theme={null}
POST /cash-registers/{id}/close
```

| Campo | Tipo | Requerido | Descripción |
| - | - | - | - |
| `declared_amount` | number | Sí | Efectivo contado al cierre (mayor o igual a 0). |
| `notes` | string | No | Máx. 500. |
| `cash_count_breakdown` | object | No | Arqueo por denominación. |
| `cash_count_breakdown.bills` | object | No | Cantidad de billetes por denominación: `hundred`, `fifty`, `twenty`, `ten`, `five`, `one` (mismo formato que el arqueo de la web). |
| `cash_count_breakdown.coins` | object | No | Cantidad de monedas: `quarter`, `dime`, `nickel`, `penny`. |
| `cash_count_breakdown.total` | number | Sí, con `cash_count_breakdown` | Debe coincidir con `declared_amount` (tolerancia 0.01). |

```bash theme={null}
curl -X POST https://api.filexpress.app/api/external/cash-registers/4e93.../close \
  -H "X-API-Key: fx_xxxxxxxx" \
  -H "Idempotency-Key: cierre-centro-20261006" \
  -H "Content-Type: application/json" \
  -d '{"declared_amount":295.00,"cash_count_breakdown":{"bills":{"hundred":0,"fifty":0,"twenty":12,"ten":5,"five":0,"one":0},"coins":{"quarter":20,"dime":0,"nickel":0,"penny":0},"total":295.00}}'
```

**Respuesta `200`**: la caja con `status: "closed"`, `closing_date`, `declared_amount`, `difference_amount` y los totales del corte.

**Reglas**

* Al cerrar se calculan las ventas por forma de pago y el **efectivo esperado** = monto inicial + ventas en efectivo + otros ingresos − gastos; `difference_amount` = declarado − esperado.
* Se cuentan las ventas procesadas vinculadas a la caja o, si no tienen caja, las emitidas en la sucursal entre la apertura y el cierre.
* El arqueo se guarda tal como se envía; FileXpress solo valida su `total`.

**Errores**

| Código | Causa |
| - | - |
| `404` | `Cash register not found`. |
| `409` | `Cash register is not open.` (ya cerrada). |
| `422` | `The cash count breakdown total does not match the declared amount.` / validación. |

<Tip>
  Abrir, registrar movimientos y cerrar aceptan [`Idempotency-Key`](/docs/api/introduccion#idempotencia): si reintentas por un fallo de red, la operación no se aplica dos veces.
</Tip>

## Errores

| Código | Cuándo |
| - | - |
| `401` | API key ausente o inválida. |
| `403` | La integración no tiene el permiso `cash_register` (o `cash_register.operate` para operar). |
| `404` | Sucursal o caja inexistente o de otro negocio. |
| `409` | Ya hay una caja abierta en la sucursal, la caja no está abierta, o conflicto de `Idempotency-Key`. |
| `422` | Validación, cajero sin acceso a la sucursal o arqueo que no coincide con lo declarado. |


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