ipsofacturaHablar con Ventas →
← Blog
CFDI 4.0Automatización

Factura Global CFDI 4.0: cómo automatizarla cuando tienes cientos de ventas al día

21 Ago 2026|8 min de lectura

En un restaurante con 300 cuentas diarias, en un comercio donde la mitad de los clientes paga en efectivo sin pedir factura, o en un e-commerce con órdenes de bajo monto que nadie factura individualmente, siempre hay una pregunta pendiente: ¿qué hacemos con todas esas ventas para el SAT?

La respuesta es la Factura Global. Y si tu sistema maneja este tipo de negocio, tarde o temprano necesitas automatizarla.


¿Qué es la Factura Global y cuándo es obligatoria?

La Factura Global es un CFDI que consolida en un solo documento todas las ventas del período donde el cliente no solicitó factura individual. No es opcional: si tienes ventas sin CFDI emitido, el SAT espera que las captures en una Factura Global.

Los casos más comunes donde aparece este requerimiento:

  • Restaurantes y cafeterías con ventas en efectivo
  • Tiendas de conveniencia, abarrotes o retail
  • Gasolineras
  • E-commerce donde el pago fue en OXXO o efectivo y el comprador nunca pidió factura

La lógica es simple: el SAT quiere que toda venta quede en algún CFDI. Si no fue en uno individual, va en la global del período.


Cómo es diferente a una factura normal

Una Factura Global no se ve tan distinta en el XML, pero tiene tres diferencias fundamentales que tu sistema debe manejar.

1. El receptor siempre es el mismo

No importa si vendiste a 500 personas distintas en el día. El receptor de la Factura Global es siempre el mismo RFC genérico del SAT:

<cfdi:Receptor
  RFC="XAXX010101000"
  Nombre="PUBLICO EN GENERAL"
  DomicilioFiscalReceptor="64000"
  RegimenFiscalReceptor="616"
  UsoCFDI="S01"/>

Estos valores son fijos. El Nombre debe ser PUBLICO EN GENERAL exactamente así, en mayúsculas. El RegimenFiscalReceptor es siempre 616 (Sin obligaciones fiscales) y el UsoCFDI es siempre S01 (Sin efectos fiscales). Si cambias cualquiera de estos, el PAC te lo rechaza con un 301.

Para ventas a extranjeros, el RFC cambia a XEXX010101000, pero el resto de los campos se mantiene igual.

2. Declara el período que consolida

Este es el elemento que no existe en ningún otro tipo de CFDI: el nodo InformacionGlobal. Es obligatorio cuando el receptor es XAXX010101000, y le dice al SAT qué período estás cerrando.

<cfdi:InformacionGlobal
  Periodicidad="04"
  Meses="08"
  Año="2025"/>

Los tres atributos son requeridos y deben ser coherentes entre sí. Las periodicidades disponibles son:

CódigoPeriodicidad
01Diaria
02Semanal
03Quincenal
04Mensual
05Bimestral

El código de Meses del 01 al 12 aplica para periodicidades diaria, semanal, quincenal y mensual. Los códigos 13 al 18 son exclusivos de la periodicidad bimestral:

CódigoBimestre
13Enero–Febrero
14Marzo–Abril
15Mayo–Junio
16Julio–Agosto
17Septiembre–Octubre
18Noviembre–Diciembre

Un error de schema frecuente es mezclar un código bimestral (1318) con Periodicidad="04" (mensual). El XSD lo rechaza.

3. Tiene plazos de cancelación distintos

La Factura Global no se puede cancelar en cualquier momento. El SAT la vincula al período fiscal que declara, y una vez que ese período cierra para efectos de declaración, la cancelación ya no es posible.

PeriodicidadLímite de cancelación
DiariaEl mismo día o el día siguiente
MensualAntes del día 17 del mes siguiente
BimestralAntes de la fecha límite de la declaración bimestral

Si intentas cancelar fuera de plazo, el SAT responde con el error CA211. Este no tiene workaround.


El flujo completo de automatización

Ahora sí, el código. El ciclo completo de una Factura Global automatizada tiene tres pasos: agrupar las ventas del período, generar el CFDI, y manejar el caso donde un cliente pide su factura individual después.

Paso 1: Identificar qué ventas van a la global

La Factura Global solo incluye ventas sin CFDI individual emitido. Tu sistema necesita llevar un registro de qué transacciones ya tienen CFDI y cuáles no:

def get_unfactured_sales(period_start: date, period_end: date) -> list[Sale]:
    return db.query("""
        SELECT * FROM sales
        WHERE date BETWEEN :start AND :end
          AND cfdi_uuid IS NULL
          AND included_in_global IS FALSE
    """, start=period_start, end=period_end)

Paso 2: Generar el payload del CFDI

El SubTotal es la suma de todas las ventas netas del período. El Total incluye impuestos. La Fecha debe caer dentro del período declarado en InformacionGlobal.

def build_factura_global(sales: list[Sale], period: Period) -> dict:
    subtotal = sum(s.amount_before_tax for s in sales)
    iva = sum(s.iva_amount for s in sales)

    return {
        "Receptor": {
            "RFC": "XAXX010101000",
            "Nombre": "PUBLICO EN GENERAL",
            "DomicilioFiscalReceptor": EMISOR_CP,
            "RegimenFiscalReceptor": "616",
            "UsoCFDI": "S01",
        },
        "InformacionGlobal": {
            "Periodicidad": period.codigo,
            "Meses": period.meses_codigo,
            "Año": str(period.year),
        },
        "TipoDeComprobante": "I",
        "MetodoPago": "PUE",
        "FormaPago": "01",   # efectivo; ajustar según la realidad del negocio
        "Exportacion": "01",
        "SubTotal": f"{subtotal:.2f}",
        "Total": f"{(subtotal + iva):.2f}",
        # ... Conceptos e Impuestos
    }

Después de timbrar, marca esas ventas como incluidas en la global:

def after_stamp(sales: list[Sale], global_uuid: str):
    sale_ids = [s.id for s in sales]
    db.execute("""
        UPDATE sales
        SET included_in_global = TRUE, global_cfdi_uuid = :uuid
        WHERE id = ANY(:ids)
    """, uuid=global_uuid, ids=sale_ids)

Paso 3: El caso edge que complica todo

El cliente llega al día siguiente y pide su factura. Tú ya la incluiste en la Factura Global de ayer.

Esto pasa más seguido de lo que parece, y el flujo correcto no es intuitivo:

  1. Emites la factura individual al RFC del cliente
  2. Cancelas la Factura Global con motivo 01 (error con relación), indicando el UUID de la factura individual como FolioSustitucion
  3. Emites una nueva Factura Global por el mismo período, excluyendo esa venta
def handle_late_invoice_request(sale_id: str, customer_rfc: str) -> dict:
    # 1. Obtener la Factura Global que contiene esa venta
    sale = db.get_sale(sale_id)
    global_uuid = sale.global_cfdi_uuid

    # 2. Emitir la factura individual primero
    individual_uuid = stamp_individual_invoice(sale_id, customer_rfc)

    # 3. Cancelar la Factura Global relacionándola con la factura individual
    cancel_cfdi(
        uuid=global_uuid,
        motivo="01",
        folio_sustitucion=individual_uuid
    )

    # 4. Re-emitir la Factura Global sin esa venta
    period = get_period_from_global(global_uuid)
    remaining_sales = get_period_sales_excluding(sale_id, period)
    new_global_uuid = stamp_factura_global(remaining_sales, period)

    return {
        "individual_uuid": individual_uuid,
        "new_global_uuid": new_global_uuid
    }

Dos cosas importantes en este flujo:

  • El motivo 01 exige FolioSustitucion. Si no lo incluyes, el SAT responde con CA208.
  • Esto solo es posible mientras estés dentro del plazo de cancelación del período. Si ya pasó el día 17 del mes siguiente para una Factura Global mensual, el CA211 bloqueará la cancelación y tendrás que resolver con el cliente de otra forma.

Los errores que más aparecen

ErrorCuándo ocurre
301El nodo InformacionGlobal está presente pero el RFC receptor no es XAXX010101000, o viceversa
Schema validation failCódigo de Meses bimestral con Periodicidad mensual
CA211Cancelación después del plazo del período fiscal
CA208Cancelación con motivo 01 sin incluir el FolioSustitucion
CA209Cancelación con motivo 02/03/04 incluyendo FolioSustitucion (no debe ir)

Checklist antes de timbrar

  • ☐ RFC receptor es exactamente XAXX010101000 para ventas nacionales
  • Nombre del receptor es PUBLICO EN GENERAL en mayúsculas
  • RegimenFiscalReceptor = 616, UsoCFDI = S01
  • ☐ Nodo InformacionGlobal presente con los tres atributos obligatorios
  • ☐ El código de Meses es coherente con la Periodicidad declarada
  • ☐ La Fecha del CFDI cae dentro del período que se está cerrando
  • ☐ El SubTotal refleja la suma real de todas las ventas incluidas
  • ☐ Las ventas incluidas están marcadas en tu base de datos antes de confirmar el timbrado

La Factura Global parece sencilla en concepto pero tiene varios puntos de falla en la implementación: los campos fijos del receptor que el SAT no negocia, la coherencia entre periodicidad y código de mes, y el flujo de cancelación cuando un cliente aparece tarde. Con el checklist y el manejo del caso edge cubiertos, tu integración aguanta los escenarios que normalmente causan problemas en producción.

¿Listo para automatizar?

Empieza a timbrar en menos de 2 horas.

Primeros 100 timbres sin costo. Sandbox listo. Sin contrato anual.

Hablar con Ventas →

Más artículos

8 min · API
Cómo integrar una API de facturación SAT en tu sistema
4 min · CFDI 4.0
Los 5 errores más comunes al timbrar CFDI 4.0