# Complementos de pago

Un **complemento de pago** es un CFDI de tipo **Pago (P)** que documenta la recepción
de un pago asociado a una factura que fue emitida con método de pago **PPD**
(Pago en parcialidades o diferido).

Este comprobante es obligatorio cuando el pago no se realiza en el momento de
la emisión de la factura original.

## Endpoint

```
POST /v1/qrs/invoices/payment-complements
```

**Host (DEV):**

```
https://api-dev.qrwey.com
```

**Host (PROD):**

```
https://api.qrwey.com
```

## Headers requeridos

```http
Authorization: Bearer {{access_token}}
Content-Type: application/json
```

## Diferencias con la factura de ingreso

| Campo | Valor para complemento de pago |
|  --- | --- |
| `type_of_receipt` | Debe ser `P` (Pago) |
| `amount` | Debe ser `0` |
| `subtotal` | Debe ser `0` |
| `currency` | Debe ser `XXX` (sin moneda) |
| `items` | No se incluye o se deja vacío |
| `sat_payment_form` | No se incluye |
| `sat_payment_method` | No se incluye |
| `exchange_rate` | No se incluye |
| `complement.payment` | **Requerido**. Contiene los datos del pago recibido |


> ⚠️ El objeto `complement.payment` es **obligatorio**. Sin el, la operación fallará.


## Request body

### Campos principales

| Campo | Descripción |
|  --- | --- |
| `sale_id` | Identificador de la operación |
| `date` | Fecha de emisión ISO 8601 (requerido) |
| `expedition_zip_code` | Código postal del lugar de expedición (requerido) |
| `amount` | **`0`** (requerido) |
| `subtotal` | **`0`** (requerido) |
| `currency` | **`XXX`** (requerido) |
| `type_of_receipt` | **`P`** (Pago) (requerido) |
| `export_code` | Código de exportación, ej. `01` (requerido) |
| `issuer` | Datos del emisor (ver [lógica de resolución](/guides/stamp-cfdi)) |
| `recipient` | Datos del receptor |
| `complement` | Objeto con los datos del pago (requerido) |


### Datos del pago (`complement.payment`)

| Campo | Descripción |
|  --- | --- |
| `payment_date` | Fecha en que se recibio el pago, formato ISO 8601 (requerido) |
| `payment_form` | Forma de pago SAT, ej. `03` Transferencia (requerido) |
| `currency` | Moneda del pago, ej. `MXN` (requerido) |
| `exchange_rate` | Tasa de cambio del pago |
| `amount` | Monto total del pago recibido (requerido) |
| `operation_number` | Número de operación o referencia bancaria |
| `source_bank_rfc` | RFC del banco emisor del pago |
| `source_account` | Cuenta bancaria del pagador |
| `target_bank_rfc` | RFC del banco receptor del pago |
| `target_account` | Cuenta bancaria del receptor |
| `related_documents` | Lista de documentos relacionados (requerido) |


### Documentos relacionados (`related_documents`)

Cada documento relacionado vincula el pago con una factura PPD emitida previamente:

| Campo | Descripción |
|  --- | --- |
| `uuid` | UUID fiscal del CFDI original (requerido) |
| `series` | Serie del CFDI original |
| `folio` | Folio del CFDI original |
| `currency` | Moneda del CFDI original (requerido) |
| `exchange_rate` | Tasa de cambio del documento |
| `installment_number` | Número de parcialidad (requerido) |
| `previous_balance` | Saldo anterior (requerido) |
| `amount_paid` | Monto pagado en esta parcialidad (requerido) |
| `remaining_balance` | Saldo restante después del pago (requerido) |
| `tax_object_code` | Clave del objeto de impuesto, ej. `02` (requerido) |
| `taxes` | Impuestos del documento relacionado (requerido cuando `tax_object_code` es `02`) |


### Impuestos del documento relacionado (`taxes`)

Cada elemento representa un impuesto aplicable al documento pagado. Estos se generan como
nodos `ImpuestosDR`, `ImpuestosP` y `Totales` en el XML del complemento de pago.

| Campo | Descripción |
|  --- | --- |
| `type` | Tipo: `Traslado` (traslado) o `Retencion` (retención) (requerido) |
| `base` | Base imponible proporcional al pago (requerido) |
| `tax` | Clave del impuesto SAT, ej. `002` IVA (requerido) |
| `factor` | Tipo de factor: `Tasa`, `Cuota` o `Exento` (requerido) |
| `rate` | Tasa o cuota del impuesto, ej. `0.160000` |
| `amount` | Monto del impuesto proporcional al pago (requerido) |


> ⚠️ Los impuestos de cada documento se acumulan automáticamente para generar los nodos `ImpuestosP` (a nivel de pago) y `Totales` (a nivel de complemento) en el XML timbrado.


## Ejemplo de request (DEV)

```bash
curl -X POST "https://api-dev.qrwey.com/v1/qrs/invoices/payment-complements" \
  -H "Authorization: Bearer {{access_token}}" \
  -H "Content-Type: application/json" \
  -d '{
    "sale_id": "pago-001-2026",
    "date": "2026-03-19T16:00:00",
    "expedition_zip_code": "06600",
    "amount": 0,
    "subtotal": 0,
    "currency": "XXX",
    "type_of_receipt": "P",
    "export_code": "01",
    "issuer": {
      "rfc": "FUNK671228PH6"
    },
    "recipient": {
      "rfc": "EKU9003173C9",
      "business_name": "ESCUELA KEMPER URGATE",
      "zip_code": "42501",
      "tax_regime_code": "601",
      "cfdi_use_code": "CP01",
      "email": "receptor@ejemplo.com"
    },
    "complement": {
      "payment": {
        "payment_date": "2026-03-18T12:00:00",
        "payment_form": "03",
        "currency": "MXN",
        "exchange_rate": 1.0,
        "amount": 5800.00,
        "operation_number": "REF-2026-0319-001",
        "source_bank_rfc": "BBA930311SEA",
        "source_account": "0123456789",
        "target_bank_rfc": "BNM840515VB1",
        "target_account": "9876543210",
        "related_documents": [
          {
            "uuid": "A1B2C3D4-E5F6-7890-ABCD-EF1234567890",
            "series": "A",
            "folio": "1001",
            "currency": "MXN",
            "exchange_rate": 1.0,
            "installment_number": 1,
            "previous_balance": 11600.00,
            "amount_paid": 5800.00,
            "remaining_balance": 5800.00,
            "tax_object_code": "02",
            "taxes": [
              {
                "type": "Traslado",
                "base": 5000.00,
                "tax": "002",
                "factor": "Tasa",
                "rate": "0.160000",
                "amount": 800.00
              }
            ]
          }
        ]
      }
    },
    "related_cfdis": null,
    "global_info": null
  }'
```

## Respuesta

```json
{
  "invoiceStatus": "GENERATED",
  "folioUuid": "R1S2T3U4-V5W6-7890-XYZA-BC1234567890",
  "sourceTaxId": "FUNK671228PH6",
  "sourceLegalName": "KARLA FUENTE NOLASCO",
  "targetTaxId": "EKU9003173C9",
  "targetLegalName": "ESCUELA KEMPER URGATE",
  "subtotal": 0,
  "iva": 0,
  "total": 0,
  "invoiceDate": "2026-03-19T16:00:00Z",
  "invoiceError": null,
  "base64Xml": "PD94bWwgdmVyc2lvbj0iMS4wIiBlb..."
}
```

> ⚠️ En el complemento de pago, los campos `subtotal`, `iva` y `total` siempre son `0`. El monto real del pago esta documentado en el nodo `complement.payment`.


La estructura de la respuesta es la misma que para [Timbrar CFDI 4.0](/guides/stamp-cfdi). Consulta esa guia para el detalle de todos los campos.

## Errores comunes

| Código | Motivo |
|  --- | --- |
| 400 | `type_of_receipt` no es `P`, `complement.payment` ausente, o `related_documents` vacío |
| 401 | Token inválido o expirado |
| 404 | Emisor no encontrado o sin llaves CSD |
| 422 | UUID del documento relacionado inválido, montos inconsistentes, o reglas del SAT no cumplidas |


Consulta: [Manejo de errores](/guides/error-handling)

## Buenas prácticas

- Emite el complemento de pago dentro de los plazos establecidos por el SAT (generalmente el día 17 del mes siguiente)
- Verifica que el UUID del documento relacionado corresponda a un CFDI con método de pago PPD
- El `installment_number` debe ser secuencial: primer pago = 1, segundo = 2, etc.
- Valida que `previous_balance - amount_paid = remaining_balance`
- El `cfdi_use_code` del receptor para complementos de pago normalmente es `CP01`
- Usa `payment_form` `03` (Transferencia electrónica) cuando el pago sea por transferencia bancaria
- Conserva el `folioUuid` para vincular el complemento con la factura original en tu contabilidad


## ¿Qué sigue?

- Emite facturas de ingreso: [Timbrar CFDI 4.0](/guides/stamp-cfdi)
- Emite notas de crédito: [Notas de crédito](/guides/credit-notes)
- Vuelve al índice: [Gestión de Clientes](/guides/customer-portal)