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

# Register Payment (Complemento de Pago)

> Send the paid invoices (`documents: [{ invoiceUuid, amount }]`, 1 to 50, same customer and currency). Timbrix computes the installment number, previous and remaining balances and proportional taxes, and stamps one Complemento de Pago 2.0. Each one counts as a CFDI of your plan.

Records a payment of one or more **PPD** invoices (pago en parcialidades o diferido) and stamps its **Complemento de Pago 2.0** (CFDI type `P`, also called REP). The SAT requires one every time you receive a payment for a PPD invoice.

You only send which invoices were paid and how much. Timbrix computes the installment number (`NumParcialidad`), the previous and remaining balances, and the proportional taxes of each invoice from its stamped XML.

## The PPD → payment flow

1. Stamp the invoice with `paymentMethod: "PPD"` and `paymentForm: "99"` ([Create Invoice](https://docs.timbrix.mx/api-reference/invoices/create.md)). Its `balance` starts at the invoice total.
2. Each time the customer pays, call this endpoint. Every call stamps one Complemento de Pago and lowers the `balance`.
3. Check the installments and balance with [Get Payments](https://docs.timbrix.mx/api-reference/invoices/get-payments.md).

## Authentication

Same as [Create Invoice](https://docs.timbrix.mx/api-reference/invoices/create.md): a Supabase session with `X-Organization-Id`, or an API key with the `write:invoices` scope (the organization and environment come from the key).

## Request Body

| Field | Type | Required | Description |
| - | - | - | - |
| `documents` | array | Yes | 1 to 50 `{ invoiceUuid, amount }`. Same customer, same currency, no repeated invoices. `amount` > 0, max 2 decimals |
| `date` | string | Yes | Payment date in Mexico City time: `YYYY-MM-DDTHH:mm:ss`, or `YYYY-MM-DD`, recorded at 12:00:00 (a SAT rule), or at the current time if the date is today and it is not yet noon. Not in the future (up to 5 minutes ahead is tolerated, to absorb clock differences), and not before the date of any of the invoices being paid (compared by calendar day). A time later than the moment the complement is stamped (for example, a payment made right now) is recorded at the complement's own date |
| `paymentForm` | string | Yes | SAT `c_FormaPago` code, e.g. `03` (transfer). `99` is not allowed |
| `currency` | string | No | Default `MXN`. Must match the invoices' currency |
| `exchange` | number | Conditional | Exchange rate to MXN. Required when `currency` is not `MXN`; ignored with `MXN` |
| `customerId` | string | No | Use this customer's current fiscal data as receptor. Its RFC must match the invoices. Default: the first invoice's receptor |
| `operationNumber` | string | No | Transfer, check or receipt reference |
| `payerBankRfc`, `payerAccount`, `payeeBankRfc`, `payeeAccount` | string | No | Bank details of the payer and the payee. Only some payment forms accept them; see [Bank details](#bank-details) |
| `series` | string | No | Default: the organization's default series for type `P` |
| `folioNumber` | string | No | Default: the next free folio of the series in this environment. A manual folio (1 to 40 characters, no vertical bar character) is used as sent and never moves the counter |
| `substitutes` | string | No | UUID of the Complemento de Pago this one replaces. The new one relates it with `TipoRelacion` `04`, pays the same invoices and keeps each one's `NumParcialidad`. See [Replacing a Complemento de Pago](#replacing-a-complemento-de-pago) |
| `idempotencyKey` | string | No | Retry safely: the same key with the same body returns the same Complemento de Pago instead of stamping again. The same key with different data, or from the other environment, returns `409` (see [Idempotency](https://docs.timbrix.mx/api-reference/invoices/create.md#idempotency)) |

Each Complemento de Pago counts as one CFDI of your plan (or of the sandbox daily limit).

> [!WARNING]
>
> **Behavior change (series and folios).** A `series` sent without `folioNumber`
> must exist in the organization: otherwise the request now returns `404
>     SERIES_NOT_FOUND`. Before, Timbrix stamped with that series and the count of
> payments plus one as the folio. Create the series first with [Create
> series](https://docs.timbrix.mx/api-reference/series/create.md), or omit `series` to use the default for
> type `P`.

> [!NOTE]
>
> Automatic folios skip numbers already used in the series (by any CFDI,
> including cancelled ones, or by a stamp in progress). A stamp that fails still
> uses its automatic folio, so the series can have a gap. The SAT does not
> require consecutive folios.

### Bank details

The SAT `c_FormaPago` catalog decides which bank details a payment form accepts and the format of each account. Timbrix checks them before stamping and returns `400` with a clear message instead of a SAT rejection. Spaces around the values are removed and the bank RFCs are uppercased; accounts are sent as written.

| `paymentForm` | Payer (`payerBankRfc`, `payerAccount`) | `payerAccount` format | Payee (`payeeBankRfc`, `payeeAccount`) | `payeeAccount` format |
| - | - | - | - | - |
| `02` Cheque nominativo | Yes | 11 or 18 digits | Yes | Card or account (see below) |
| `03` Transferencia electrónica | Yes | 10, 16 or 18 digits | Yes | 10 digits or an 18-digit CLABE |
| `04` Tarjeta de crédito | Yes | 16 digits | Yes | Card or account |
| `05` Monedero electrónico | Yes | Card or account | Yes | Card or account |
| `06` Dinero electrónico | Yes | 10 digits | No | — |
| `28` Tarjeta de débito | Yes | 16 digits | Yes | Card or account |
| `29` Tarjeta de servicios | Yes | 15 or 16 digits | Yes | Card or account |
| Any other (`01` Efectivo, `17`, `30`…) | No | — | No | — |

"Card or account" means 10, 11, 15, 16 or 18 digits, or 10 to 50 uppercase letters, digits or underscores.

`payerBankRfc` and `payeeBankRfc` must be the 12-character RFC of a Mexican bank. Foreign banks (`XEXX010101000`) are not supported yet: leave `payerBankRfc` out.

## Example

```bash theme={null}
curl -X POST https://api.timbrix.mx/invoices/payments \
  -H "X-API-Key: sk_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "date": "2026-10-15T12:00:00",
    "paymentForm": "03",
    "operationNumber": "SPEI-123",
    "documents": [
      { "invoiceUuid": "d3bfbc57-44af-4390-a064-f0afab85e5df", "amount": 500 },
      { "invoiceUuid": "7c3d5e1f-2a4b-4c6d-8e0f-1a2b3c4d5e6f", "amount": 1160 }
    ],
    "idempotencyKey": "pago-8421"
  }'
```

```ts theme={null}
const rep = await timbrix.invoices.registerPayment({
  date: "2026-10-15T12:00:00",
  paymentForm: "03",
  documents: [
    { invoiceUuid: "d3bfbc57-44af-4390-a064-f0afab85e5df", amount: 500 },
  ],
})
console.log(rep.payment?.documents[0]?.remainingBalance)
```

## Response

The same shape as any invoice (`type: "P"`, `total: 0`), plus a `payment` block:

```json theme={null}
{
  "id": "…",
  "uuid": "9a8b7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d",
  "type": "P",
  "series": "P",
  "folioNumber": "12",
  "total": 0,
  "paymentMethod": null,
  "balance": null,
  "payment": {
    "date": "2026-10-15T12:00:00",
    "paymentForm": "03",
    "currency": "MXN",
    "exchange": 1,
    "amount": 1660,
    "operationNumber": "SPEI-123",
    "documents": [
      {
        "invoiceUuid": "d3bfbc57-…",
        "installment": 2,
        "previousBalance": 660,
        "amountPaid": 500,
        "remainingBalance": 160
      },
      {
        "invoiceUuid": "7c3d5e1f-…",
        "installment": 1,
        "previousBalance": 1160,
        "amountPaid": 1160,
        "remainingBalance": 0
      }
    ]
  }
}
```

If the customer's RFC appears as **Presunto** in the SAT's 69-B list, the complement is stamped anyway and the response adds `warnings: [{ "code": "RFC_69B_PRESUNTO", "rfc": "…", "role": "receptor", "message": "…" }]` (only present when there are warnings; a retry with the same `idempotencyKey` returns the original response without new ones). If it appears as **Definitivo** and every paid invoice was stamped to that same RFC, the complement is also stamped, because it complements CFDI already issued, and the warning has `code` `RFC_69B_DEFINITIVO`. See [Lista 69-B del SAT](https://docs.timbrix.mx/lista-69b.md).

## Errors

| Case | HTTP | Message |
| - | - | - |
| Your RFC is Definitivo in the 69-B list (production), or the customer's RFC is Definitivo and a paid invoice was stamped to a different RFC | 422 | `RFC_IN_69B_LIST`. Receptor: El RFC del receptor {rfc} aparece como Definitivo en la lista 69-B del SAT (publicado el {fecha}). Timbrix no permite timbrar nuevos CFDI a este receptor. Emisor: Tu RFC {rfc} aparece como Definitivo en la lista 69-B del SAT (publicado el {fecha}). No puedes timbrar nuevos CFDI. Si ya desvirtuaste o tienes sentencia favorable, contacta a soporte. |
| Invoice is PUE | 422 | La factura {uuid} se emitió con pago en una sola exhibición (PUE) y no lleva complemento de pago |
| Amount above the balance | 422 | El monto ({monto}) es mayor al saldo pendiente de la factura {uuid} ({saldo}) |
| Invoices of different customers | 422 | Todas las facturas de un pago deben ser del mismo cliente |
| Different currency | 422 | El pago debe ir en la misma moneda que la factura {uuid} ({moneda}) |
| Invoice cancelled or being cancelled | 409 | La factura {uuid} está cancelada o en proceso de cancelación |
| Same `idempotencyKey` still being confirmed | 409 | `PAC_STAMP_PENDING`: retry later with the same key |
| `folioNumber` already used by another CFDI of the organization in this environment (cancelled ones count) | 409 | `FOLIO_ALREADY_USED`: La factura {serie}-{folio} ya existe. |
| `series` sent without `folioNumber` and it does not exist | 404 | `SERIES_NOT_FOUND` |
| Invoice is not an Ingreso | 422 | La factura {uuid} no es de ingreso; solo las facturas de ingreso llevan complemento de pago |
| Invoice has no PPD payment method | 422 | La factura {uuid} no indica pago en parcialidades o diferido (PPD) y no lleva complemento de pago |
| Repeated invoice in `documents` | 400 | La factura {uuid} aparece más de una vez en el pago |
| Future payment date | 400 | La fecha del pago no puede ser futura |
| Date before any invoice's date | 400 | La fecha del pago no puede ser anterior a la fecha de la factura {uuid} |
| Invoice from the other environment | 400 | La factura {uuid} pertenece a otro ambiente (sandbox o producción) que esta solicitud |
| Bank detail the payment form does not take | 400 | La forma de pago {clave} ({nombre}) no lleva {campo} |
| Account with the wrong format | 400 | La {campo} no es válida para la forma de pago {clave} ({nombre}): debe tener {formatos} |
| Invalid bank RFC | 400 | El {campo} no es válido: debe ser el RFC de 12 caracteres de un banco mexicano |
| Foreign bank RFC | 400 | Todavía no se admiten bancos extranjeros (XEXX010101000): omite el {campo} |
| Invoice or customer not found | 404 | No encontramos la factura {uuid} / No encontramos el cliente {id} |
| Malformed `date` | 400 | La fecha del pago debe tener el formato AAAA-MM-DDTHH:mm:ss (hora de la Ciudad de México) |
| Invoice XML cannot be read | 422 | No pudimos leer el XML de la factura {uuid} |
| Invoice issued with another RFC | 422 | La factura {uuid} se emitió con otro RFC emisor y no se le puede registrar el pago desde esta organización |
| Customer has no fiscal zip code | 422 | El cliente no tiene código postal fiscal; agrégalo antes de registrar el pago |
| Taxes cannot be computed | 422 | No pudimos calcular los impuestos de la factura {uuid} a partir de su XML |
| `idempotencyKey` used by another CFDI | 409 | La idempotencyKey {key} ya se usó para un CFDI que no es complemento de pago |
| `idempotencyKey` reused with other data | 409 | La idempotencyKey {key} ya se usó con otros datos. Si es otro CFDI, usa una llave distinta |
| `idempotencyKey` from the other environment | 409 | La idempotencyKey {key} ya se usó en {producción/sandbox}; usa una llave distinta en {sandbox/producción} |
| SAT rejection (`CRP…` codes) | 400 | The SAT's message |
| `substitutes` not found | 404 | No encontramos el complemento de pago {uuid} |
| `substitutes` is not a Complemento de Pago | 400 | El CFDI {uuid} no es un complemento de pago; para sustituir una factura usa relatedCfdis con TipoRelacion 04 |
| `substitutes` from the other environment | 400 | El complemento de pago {uuid} pertenece a otro ambiente (sandbox/producción) |
| Replacement pays other invoices | 400 | El sustituto debe liquidar las mismas facturas que el complemento {uuid}: {uuids} |
| Original being cancelled | 409 | El complemento de pago {uuid} tiene una cancelación en proceso o pendiente; espera a que se resuelva |
| Original already replaced | 409 | El complemento de pago {uuid} ya tiene un sustituto ({uuid}); cancélalo con motivo 01 y folioSustitucion {uuid} |
| Original replaces another one still vigente | 409 | El complemento de pago {uuid} sustituye a {uuid}, que sigue vigente; cancela primero {uuid} con motivo 01 y folioSustitucion {uuid} |
| Replacement still being stamped | 409 | El complemento de pago {uuid} ya tiene un sustituto en timbrado; reintenta en unos minutos |
| Installment number taken | 409 | La parcialidad {n} de la factura {uuid} ya la tiene otro complemento de pago vigente |
| Amount changed with later installments | 422 | La factura {uuid} tiene parcialidades posteriores a la {n}: el sustituto debe pagar el mismo monto ({monto}) para no romper la cadena de saldos |

Other request validation errors (`paymentForm` `99`, more than 2 decimals, 1 to 50 `documents`) return `400`.

Two payments sent at the same time for the same invoice never exceed its balance: the second one sees the first one while it is being stamped.

## Credit notes

A vigente credit note (Egreso related to the invoice with `TipoRelacion` `01`) reduces the invoice balance: `balance = total − credit notes − payments`. A PPD invoice of 1160.00 with a credit note of 160.00 has a balance of 1000.00, and a payment of 1000.00 is stamped with `NumParcialidad` 1, `ImpSaldoAnt` 1000.00 and `ImpSaldoInsoluto` 0.00, as in the SAT's filling guide.

The `ImpuestosDR` are prorated over what is left of the invoice: `factor = ImpPagado / (Total − credit notes)`, applied to the invoice taxes minus the credit notes' taxes (by tax, factor type and rate). If a credit note has a tax or rate the invoice does not have, the payment returns `422` (taxes cannot be computed).

Cancelling a credit note puts its amount back in the balance. If payments were registered after the credit note, cancel those Complementos de Pago first and register them again, so each one's balances stay consistent.

While a credit note for the invoice is being stamped, a payment for that invoice returns `409` ("La factura {uuid} tiene una nota de crédito en timbrado; reintenta en unos minutos"): its amount and taxes are not confirmed yet. Retry once the credit note is stamped (or confirmed as not stamped). A credit note and a payment sent at the same time for the same invoice never exceed its balance together.

## Webhooks

Each Complemento de Pago sends `invoice.stamped` (with `tipoComprobante: "P"`) and [`invoice.payment_received`](https://docs.timbrix.mx/api-reference/webhooks/create) (payload documented there).

## Cancelling

A Complemento de Pago is cancelled directly (no receptor approval) with [Cancel Invoice](https://docs.timbrix.mx/api-reference/invoices/cancel.md). Its amount goes back to the invoice balance. To fix one, replace it (below) and cancel it with `motivo` `01`; `motivo` `02` cancels it without a replacement. To cancel a PPD invoice, first cancel its Complementos de Pago.

## Replacing a Complemento de Pago

To correct a Complemento de Pago (A), stamp its replacement (B) with `substitutes` set to A's UUID, then cancel A with `motivo` `01` and `folioSustitucion` set to B's UUID. B carries `CfdiRelacionados` with `TipoRelacion` `04` pointing at A, and `relatedCfdis` in the response shows it.

```bash theme={null}
curl -X POST https://api.timbrix.mx/invoices/payments \
  -H "Authorization: Bearer sk_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "substitutes": "9a8b7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d",
    "date": "2026-10-15T12:00:00",
    "paymentForm": "03",
    "documents": [{ "invoiceUuid": "d3bfbc57-44af-4390-a064-f0afab85e5df", "amount": 500 }]
  }'
```

* B must pay **the same invoices** as A. Payment date, payment form, bank details and the receptor can change.
* Each invoice keeps the `NumParcialidad` it had in A.
* If A is the invoice's last installment that counts, `ImpSaldoAnt` is recomputed from the current balance (credit notes included) and the amount can be corrected.
* If later installments exist, B keeps A's `ImpSaldoAnt` and must pay the same amount, so the balances of the later installments stay consistent.
* While B is vigente or being stamped, A no longer counts against the balance, even before you cancel it. If B fails or is cancelled, A counts again. [Get Invoice Payments](https://docs.timbrix.mx/api-reference/invoices/get-payments.md) shows `substitutedByUuid` on A.
* A can also be **already cancelled** (for example with `motivo` `02`): B reissues that installment with its original number. If another vigente Complemento de Pago already uses that `NumParcialidad` for the invoice, the request returns `409`.
* Cancel A with `motivo` `01` and `folioSustitucion` = B. Until then both are vigente at the SAT.


## OpenAPI

````yaml POST /invoices/payments
openapi: 3.0.0
info:
  title: Timbrix API
  description: >-
    API de facturación electrónica CFDI 4.0 para México, con servidor OAuth2
    para gestionar organizaciones, miembros y webhooks. Compatible con agentes
    de IA — ver la extensión `x-ai-agent-friendly` en la raíz de esta spec.


    REST API with OAuth2 server for managing organizations, members, and
    webhooks.
  version: '1.0'
  contact: {}
servers: []
security: []
tags:
  - name: organizations
    description: Organization management endpoints
  - name: oauth
    description: OAuth2 authentication and authorization
  - name: webhooks
    description: Webhook configuration and delivery
  - name: users
    description: User information endpoints
  - name: api-keys
    description: API Keys management and validation
  - name: request-logs
    description: API request log
paths:
  /invoices/payments:
    post:
      tags:
        - invoices
      summary: >-
        Register a payment of PPD invoices and stamp its Complemento de Pago
        (CFDI tipo P)
      description: >-
        Send the paid invoices (`documents: [{ invoiceUuid, amount }]`, 1 to 50,
        same customer and currency). Timbrix computes the installment number,
        previous and remaining balances and proportional taxes, and stamps one
        Complemento de Pago 2.0. Each one counts as a CFDI of your plan.
      operationId: InvoicesController_registerPayment
      parameters:
        - name: x-timbrix-client
          required: true
          in: header
          schema:
            type: string
        - name: X-Timbrix-Client
          in: header
          description: 'Canal de origen del CFDI: web, api, sdk, cli o mcp.'
          required: false
          schema:
            type: string
        - name: X-Organization-Id
          in: header
          description: >-
            Required for Supabase session auth. Ignored when authenticating with
            an API key (the organization resolves from the key).
          required: false
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RegisterPaymentDto'
      responses:
        '201':
          description: ''
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/InvoiceResponseDto'
        '400':
          description: Invalid payload, future payment date or SAT rejection
        '404':
          description: An invoice or customer was not found
        '409':
          description: >-
            An invoice is cancelled or being cancelled, or a stamp with this
            idempotencyKey is still being confirmed
        '422':
          description: >-
            Invoice is not PPD, amount exceeds the balance, different customer
            or currency
      security:
        - apiKey: []
        - bearer: []
components:
  schemas:
    RegisterPaymentDto:
      type: object
      properties:
        customerId:
          type: string
          description: >-
            Cliente registrado. Si se omite, el receptor del complemento sale de
            la primera factura. Si se envía, su RFC debe ser el de todas las
            facturas.
        date:
          type: string
          example: '2026-10-15T12:00:00'
          description: Fecha y hora del pago en la Ciudad de México (sin zona horaria)
        paymentForm:
          type: string
          example: '03'
          description: Forma de pago del catálogo c_FormaPago del SAT (sin 99)
        currency:
          type: string
          example: MXN
          description: 'Default: MXN. Debe ser la moneda de las facturas.'
        exchange:
          type: number
          example: 18.5
          description: >-
            Tipo de cambio a MXN. Obligatorio si `currency` no es MXN; se ignora
            con MXN.
        operationNumber:
          type: string
          example: SPEI-123
          description: Número o referencia de la operación
        payerBankRfc:
          type: string
          description: RFC del banco del que paga
        payerAccount:
          type: string
          description: Cuenta del que paga
        payeeBankRfc:
          type: string
          description: RFC del banco que recibe
        payeeAccount:
          type: string
          description: Cuenta que recibe
        series:
          type: string
          example: P
          description: 'Serie del complemento. Default: P'
        folioNumber:
          type: string
          example: '12'
          description: >-
            Folio del complemento. Si se omite, Timbrix usa el siguiente de la
            organización.
        documents:
          description: Facturas PPD que liquida este pago (1 a 50)
          type: array
          items:
            $ref: '#/components/schemas/PaymentDocumentDto'
        substitutes:
          type: string
          example: 5f0e7c4b-2a8d-4c1e-9b3a-7d6f1e2c3b4a
          description: >-
            Folio fiscal (UUID) del complemento de pago que este sustituye
            (CfdiRelacionados 04). Debe liquidar las mismas facturas; cada una
            conserva su número de parcialidad. Si el original sigue vigente,
            cancélalo después con motivo 01.
        idempotencyKey:
          type: string
          example: pago-8421
          description: Llave para reintentar sin timbrar dos veces el mismo complemento
      required:
        - date
        - paymentForm
        - documents
    InvoiceResponseDto:
      type: object
      properties:
        id:
          type: string
          description: Timbrix invoice record ID
          example: 0f2a1c3e-1a2b-4c3d-9e8f-1234567890ab
        uuid:
          type: string
          description: Folio fiscal UUID asignado por el SAT vía PAC
          example: d3bfbc57-44af-4390-a064-f0afab85e5df
        status:
          type: string
          enum:
            - vigente
            - cancelado
          example: vigente
          description: >-
            Estado fiscal del CFDI registrado en Timbrix: vigente o cancelado.
            Antes de TIM-243 este campo era siempre "valid". Con una cancelación
            pendiente (cancellationStatus: pendiente) cuyo plazo de respuesta
            del receptor ya venció, el SAT pudo haberlo cancelado
            automáticamente; confírmalo en el portal del SAT.
        cancellationStatus:
          type: string
          enum:
            - pendiente
            - rechazada
            - en_proceso
          nullable: true
          description: >-
            Latest cancellation attempt's status, only while the invoice is
            still vigente. null if never attempted or already cancelado. A
            pendiente past the receptor's response deadline may already be
            cancelado at the SAT. en_proceso: the cancellation was sent and its
            outcome is being confirmed with the SAT; don't treat the CFDI as
            vigente yet.
        cancellationDesynced:
          type: boolean
          description: >-
            true when a cancellation was accepted but the invoice status update
            failed to apply — indicates the invoice may already be cancelled at
            the SAT even though it still shows vigente here; needs manual
            reconciliation.
          example: false
        type:
          type: string
          enum:
            - I
            - E
            - T
            - P
          example: I
          description: I = Ingreso, E = Egreso, T = Traslado, P = Pago
        series:
          type: string
          example: A
        folioNumber:
          type: string
          example: '1'
        total:
          type: number
          example: 116
        date:
          type: string
          example: '2026-07-30T22:50:00'
        xml:
          type: string
          description: XML del CFDI timbrado (UTF-8)
        createdAt:
          type: string
          example: '2026-07-30T22:50:03.412Z'
        environment:
          type: string
          enum:
            - sandbox
            - production
          example: production
          description: >-
            Ambiente en el que se timbró el CFDI. Los CFDI de sandbox no tienen
            validez fiscal ante el SAT.
        channel:
          type: string
          enum:
            - web
            - api
            - sdk
            - cli
            - mcp
          nullable: true
          example: mcp
          description: >-
            Canal de origen declarado por el cliente con el header
            X-Timbrix-Client (api si no se envió). null para CFDI anteriores a
            este campo.
        rfcReceptor:
          type: string
          example: GODE561231GR8
          description: RFC del receptor del CFDI
        relatedCfdis:
          description: >-
            Relaciones de este CFDI (CfdisRelacionados). Con tipo 04 apunta al
            CFDI que sustituye.
          type: array
          items:
            $ref: '#/components/schemas/RelatedCfdiResponseDto'
        substitutedBy:
          description: >-
            CFDI cuya relación 04 apunta a este comprobante (sustitutos
            emitidos).
          type: array
          items:
            $ref: '#/components/schemas/SubstituteSummaryResponseDto'
        paymentMethod:
          type: string
          enum:
            - PUE
            - PPD
          nullable: true
          example: PPD
          description: >-
            Método de pago; null en Traslado, Pago y facturas anteriores a este
            campo.
        balance:
          type: object
          nullable: true
          example: 160
          description: >-
            Saldo pendiente de una factura PPD (total menos complementos de pago
            vigentes o en timbrado); null en las demás.
        payment:
          description: >-
            Solo en complementos de pago (type P): el pago y las facturas que
            liquida.
          allOf:
            - $ref: '#/components/schemas/InvoicePaymentDto'
      required:
        - id
        - uuid
        - status
        - cancellationStatus
        - cancellationDesynced
        - type
        - series
        - folioNumber
        - total
        - date
        - xml
        - createdAt
        - environment
        - channel
        - rfcReceptor
        - relatedCfdis
        - substitutedBy
        - paymentMethod
        - balance
    PaymentDocumentDto:
      type: object
      properties:
        invoiceUuid:
          type: string
          example: d3bfbc57-44af-4390-a064-f0afab85e5df
          description: Folio fiscal (UUID) de la factura PPD que se paga
        amount:
          type: number
          example: 500
          description: Monto que se paga de esta factura, en su moneda
      required:
        - invoiceUuid
        - amount
    RelatedCfdiResponseDto:
      type: object
      properties:
        type:
          type: string
          enum:
            - '01'
            - '02'
            - '03'
            - '04'
            - '05'
            - '06'
            - '07'
          example: '04'
          description: Clave de c_TipoRelacion (04 = sustitución)
        uuids:
          example:
            - D3BFBC57-44AF-4390-A064-F0AFAB85E5DF
          description: UUID de los CFDI relacionados
          type: array
          items:
            type: string
      required:
        - type
        - uuids
    SubstituteSummaryResponseDto:
      type: object
      properties:
        uuid:
          type: string
          example: 6F2B1C9A-3D4E-4F5A-8B7C-9D0E1F2A3B4C
        serie:
          type: string
          example: A
        folio:
          type: string
          example: '124'
        status:
          type: string
          enum:
            - vigente
            - cancelado
          example: vigente
      required:
        - uuid
        - serie
        - folio
        - status
    InvoicePaymentDto:
      type: object
      properties:
        date:
          type: string
          example: '2026-10-15T12:00:00'
        paymentForm:
          type: string
          example: '03'
        currency:
          type: string
          example: MXN
        exchange:
          type: number
          example: 1
        amount:
          type: number
          example: 1660
        operationNumber:
          type: object
          nullable: true
          example: SPEI-123
        documents:
          type: array
          items:
            $ref: '#/components/schemas/InvoicePaymentDocumentDto'
      required:
        - date
        - paymentForm
        - currency
        - exchange
        - amount
        - operationNumber
        - documents
    InvoicePaymentDocumentDto:
      type: object
      properties:
        invoiceUuid:
          type: string
          example: d3bfbc57-44af-4390-a064-f0afab85e5df
        installment:
          type: number
          example: 2
        previousBalance:
          type: number
          example: 660
        amountPaid:
          type: number
          example: 500
        remainingBalance:
          type: number
          example: 160
      required:
        - invoiceUuid
        - installment
        - previousBalance
        - amountPaid
        - remainingBalance
  securitySchemes:
    apiKey:
      type: apiKey
      in: header
      name: X-API-Key
      description: 'API Key for authentication (format: sk_...)'
    bearer:
      scheme: bearer
      bearerFormat: JWT
      type: http

````

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