> ## 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.

# Cuentas por cobrar

> Facturas con saldo, resumen vigente/vencido, historial y registro de cobros

| Permiso | Endpoints |
| - | - |
| `receivables` | `GET /receivables`, `GET /receivables/summary`, `GET /receivables/{sale_id}/payments` |
| `receivables.payments` | `POST /receivables/payments`, `POST /receivables/payments/{payment_id}/reverse` |

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

<Tip>
  El `bank_id` se obtiene con [Bancos, cajas chicas y chequeras](/docs/api/tesoreria) (permiso `treasury`).
</Tip>

Consulta las facturas de clientes con saldo pendiente y aplica cobros. Usa la misma lógica que **Cuentas por cobrar** en FileXpress.

## Documentos pendientes

```http theme={null}
GET /receivables?branch_id={branch_id}&customer_id={customer_id}
```

| Parámetro | Tipo | Requerido | Descripción |
| - | - | - | - |
| `branch_id` | string | Sí | Sucursal. |
| `customer_id` | string | No | Filtra por cliente. |

Incluye las facturas **procesadas** de tipo CCF, FC y FEX con saldo pendiente, del ambiente del negocio, excluyendo las invalidadas por un documento relacionado.

```json theme={null}
{
  "status": true,
  "data": {
    "data": [
      {
        "sale_id": "9a10...",
        "generation_code": "DTE-03-M001P001-000000000000123",
        "document_type": "ccf",
        "issue_date": "2026-08-20",
        "due_date": "2026-09-19",
        "days_overdue": 17,
        "customer_id": "9c77...",
        "customer_name": "Grupo Alfa, S.A. de C.V.",
        "total_amount": 1130.0,
        "amount_paid": 500.0,
        "pending_amount": 630.0,
        "payment_status": "partial"
      }
    ],
    "total_pending": 630.0
  }
}
```

| Campo | Descripción |
| - | - |
| `due_date` | Fecha de emisión + días de crédito del documento (30 si no tiene). |
| `days_overdue` | Días transcurridos desde el vencimiento (0 si está vigente). |
| `customer_name` | Razón social o, si no tiene, nombre comercial. |
| `amount_paid` | Suma de cobros aplicados (los revertidos no cuentan). |
| `payment_status` | `pending` (sin cobros) o `partial` (con abonos). |
| `total_pending` | Suma de `pending_amount` del listado. |

Ordenado del documento más antiguo al más reciente. **Errores**: `404` `Branch not found`; `422` validación.

## Resumen vigente / vencido

```http theme={null}
GET /receivables/summary?branch_id={branch_id}
```

```json theme={null}
{
  "status": true,
  "data": {
    "total": 15420.5,
    "current": 9800.0,
    "overdue": 5620.5,
    "current_count": 14,
    "overdue_count": 6
  }
}
```

`current` suma los documentos con `days_overdue = 0`; `overdue`, los vencidos. `branch_id` es obligatorio: sin él (o de otro negocio) responde `404` `Branch not found`.

## Historial de cobros

```http theme={null}
GET /receivables/{sale_id}/payments
```

```json theme={null}
{
  "status": true,
  "data": [
    {
      "id": "9f20...",
      "amount": "500.00",
      "pay_date": "2026-09-05 14:12:00",
      "reference": "TRF-88231",
      "status": "applied",
      "payment_method_name": "Transferencia bancaria",
      "bank_name": "Banco Agrícola"
    }
  ]
}
```

Incluye todos los cobros del documento en orden de fecha, también los revertidos (`status` distinto de `applied`). **Errores**: `404` `Invoice not found` (inexistente o de otro negocio).

## Registrar cobro

```http theme={null}
POST /receivables/payments
```

Hay dos formas de indicar a qué documentos aplicar el cobro:

<Tabs>
  <Tab title="Por documento (allocations)">
    Indicas cada factura y el monto a aplicarle.

    ```json theme={null}
    {
      "payment_method_id": "pm-uuid",
      "bank_id": "bank-uuid",
      "payment_date": "2026-10-06",
      "reference_number": "TRF-90112",
      "allocations": [
        { "sale_id": "9a10...", "amount": 630.00 },
        { "sale_id": "9a14...", "amount": 250.00 }
      ]
    }
    ```
  </Tab>

  <Tab title="Automático por cliente">
    Indicas el cliente, la sucursal y el monto total; FileXpress lo reparte **del documento más antiguo al más reciente** hasta agotarlo.

    ```json theme={null}
    {
      "payment_method_id": "pm-uuid",
      "bank_id": "bank-uuid",
      "payment_date": "2026-10-06",
      "customer_id": "9c77...",
      "branch_id": "9d1c5a3e-...",
      "amount": 880.00
    }
    ```
  </Tab>
</Tabs>

| Campo | Tipo | Requerido | Descripción |
| - | - | - | - |
| `payment_method_id` | string | Sí | Forma de pago (ver [catálogos](/docs/api/facturacion/catalogos)). |
| `payment_date` | date | Sí | Fecha del cobro `YYYY-MM-DD` (se guarda con la hora actual). |
| `bank_id` | string | No | Banco donde se deposita el cobro (del negocio). |
| `reference_number` | string | No | Referencia (máx. 255). |
| `notes` | string | No | Máx. 500. |
| `allocations` | array | Sí, si no se envía `customer_id` | 1 a 200 elementos. |
| `allocations[].sale_id` | string | Sí, con `allocations` | Factura (venta) del negocio. |
| `allocations[].amount` | number | Sí, con `allocations` | Mayor que 0 y no mayor que su saldo pendiente. |
| `customer_id` | string | Sí, si no se envía `allocations` | Cliente. |
| `branch_id` | string | Sí, con `customer_id` | Sucursal de los documentos. |
| `amount` | number | Sí, con `customer_id` | Monto total; no puede exceder el saldo pendiente total del cliente en la sucursal. |

**Reglas**

* **Todo o nada**: los cobros se aplican en una sola transacción. Si un documento falla, no se aplica ninguno.
* El monto de cada documento no puede superar su saldo pendiente; al cubrirlo por completo pasa a `payed`, si no a `partial`.
* Si envías `bank_id`, el banco debe pertenecer al negocio; se registra el depósito.
* Se recomienda enviar [`Idempotency-Key`](/docs/api/introduccion#idempotencia) para no duplicar el cobro si reintentas.
* Los cobros registrados quedan listos para contabilizarse en [Procesar documentos](/docs/contabilidad/procesar-documentos) (tipo **Pagos de clientes**).

```bash theme={null}
curl -X POST https://api.filexpress.app/api/external/receivables/payments \
  -H "X-API-Key: fx_xxxxxxxx" \
  -H "Idempotency-Key: cobro-banco-20261006-0042" \
  -H "Content-Type: application/json" \
  -d '{"payment_method_id":"pm-uuid","payment_date":"2026-10-06","customer_id":"9c77...","branch_id":"9d1c5a3e-...","amount":880.00}'
```

**Respuesta `201`**

```json theme={null}
{
  "status": true,
  "data": {
    "payments": [
      {
        "payment_id": "9f31...",
        "sale_id": "9a10...",
        "generation_code": "DTE-03-M001P001-000000000000123",
        "amount": 630.0,
        "pending_amount": 0.0,
        "payment_status": "payed"
      },
      {
        "payment_id": "9f32...",
        "sale_id": "9a14...",
        "generation_code": "DTE-03-M001P001-000000000000131",
        "amount": 250.0,
        "pending_amount": 150.0,
        "payment_status": "partial"
      }
    ],
    "total_applied": 880.0
  }
}
```

**Errores**

| Código | Causa |
| - | - |
| `404` | `Invoice <id> not found` (en `allocations`, de otro negocio o inexistente) / `Branch not found`. |
| `422` | Validación (`Validation errors` con `errors`). |
| `422` | `Payment method not found` / `Bank not found` (de otro negocio o inexistente). |
| `422` | `The amount exceeds the customer pending balance.` (modo automático). |
| `422` | `El monto para la factura <código> excede lo pendiente. Pendiente: <monto>` / `La factura <código> ya está pagada.` |
| `409` | Conflicto de `Idempotency-Key`. |

## Revertir cobro

```http theme={null}
POST /receivables/payments/{payment_id}/reverse
```

Anula un cobro aplicado. Requiere el permiso `receivables.payments`. El `payment_id` es el devuelto al registrar el cobro o el `id` del historial.

| Campo | Tipo | Requerido | Descripción |
| - | - | - | - |
| `reason` | string | No | Motivo (máx. 500). Solo se devuelve en la respuesta; no se guarda. |

```bash theme={null}
curl -X POST https://api.filexpress.app/api/external/receivables/payments/9f31.../reverse   -H "X-API-Key: fx_xxxxxxxx"   -H "Idempotency-Key: reversa-cobro-9f31"   -H "Content-Type: application/json"   -d '{"reason":"Cobro duplicado"}'
```

**Respuesta `200`**

```json theme={null}
{
  "status": true,
  "data": {
    "reversed_payment": {
      "payment_id": "9f31...",
      "original_amount": 630.0,
      "reversal_reason": "Cobro duplicado",
      "reversed_at": "2026-10-06T15:40:12-06:00"
    },
    "sale_info": {
      "sale_id": "9a10...",
      "generation_code": "DTE-03-M001P001-000000000000123",
      "total_amount": 1130.0,
      "total_paid": 500.0,
      "pending_amount": 630.0,
      "payment_status": "partial"
    },
    "accounting": {
      "action": "reversed",
      "journal_entry_id": "b7c2...",
      "entry_code": "DIA-000145",
      "status": "PROCESADA"
    }
  }
}
```

**Reglas**

* El cobro queda con `status: "reversed"` y deja de contar en el saldo; el `payment_status` de la factura se recalcula (`pending`, `partial` o `payed`).
* Se compensa el depósito bancario que generó el cobro.
* `accounting` indica qué pasó con la partida contable del cobro (ver [Reversión de pagos y su partida](/docs/contabilidad/procesar-documentos#reversion-de-pagos-y-su-partida)): `none` (aún no contabilizado; `journal_entry_id`, `entry_code` y `status` en `null`), `deleted` (la partida estaba en Borrador y se marcó `ELIMINADA`) o `reversed` (se creó una partida espejo con referencia `payment_received_reversal`, fechada hoy; `status` según el ajuste *Estado al procesar* correspondiente).
* Sin `reason`, `reversal_reason` es `Payment reversed`.
* Se recomienda enviar [`Idempotency-Key`](/docs/api/introduccion#idempotencia).

**Errores**

| Código | Causa |
| - | - |
| `404` | `Payment not found` (inexistente o de otro negocio). |
| `409` | `El cobro ya fue revertido.` / conflicto de `Idempotency-Key`. |
| `422` | Validación (`reason` de más de 500 caracteres) / `No se pudo revertir la partida contable del cobro: …` (p. ej. no hay período abierto para hoy); el cobro no se revierte. |


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