Skip to main content

Overview

Luis IT Repair includes built-in support for Mexican CFDI (Comprobante Fiscal Digital por Internet) electronic invoicing. This guide covers:
  • CFDI 4.0 configuration
  • SAT catalog integration
  • PAC (Proveedor Autorizado de Certificacion) setup
  • Invoice generation and stamping
  • Folio management
  • Tax compliance
This feature requires valid RFC, digital certificates (CSD), and a PAC provider contract.

CFDI Basics

What is CFDI?

CFDI (Comprobante Fiscal Digital por Internet) is Mexico’s electronic invoicing standard mandated by SAT (Servicio de Administracion Tributaria). It replaces paper invoices and is legally required for:
  • B2B transactions
  • B2C transactions over $2,000 MXN
  • Any transaction where the customer requests an invoice

CFDI 4.0 Structure

A CFDI includes:
  1. Emisor (Issuer): Your business information
  2. Receptor (Receiver): Customer information
  3. Conceptos (Line Items): Products/services sold
  4. Impuestos (Taxes): IVA, ISR, etc.
  5. Complementos (Complements): Additional data (optional)
  6. Sello Digital (Digital Stamp): Cryptographic signature
  7. Timbre Fiscal Digital (SAT Stamp): PAC validation

Configuration

Enable Billing Module

1

Navigate to POS Settings

Go to Configuracion > POS y Facturacion > Facturacion
2

Enable Invoicing

Check the box:
☑ Habilitar facturacion en POS
3

Select Emission Mode

Choose how invoices are issued:
  • Ticket y factura: Print both receipt and invoice
  • Factura bajo solicitud: Invoice only when customer requests
  • Solo factura: Always invoice (no receipt)

Issuer Information (Emisor)

razonSocial
string
required
Your business legal name as registered with SATExample: "Servicios Tecnologicos Luis IT Repair S.A. de C.V."
rfcEmisor
string
required
Your business RFC (Tax ID)Format:
  • Persona Moral: 12 characters (e.g., ABC123456D01)
  • Persona Fisica: 13 characters (e.g., XAXX010101000)
This must match your SAT registration exactly.
regimenFiscal
string
required
Your tax regime code from SAT catalogCommon values:
  • 601: General de Ley Personas Morales
  • 612: Personas Fisicas con Actividades Empresariales y Profesionales
  • 626: Regimen Simplificado de Confianza
Full SAT Catalog c_RegimenFiscal
codigoPostalEmisor
string
required
Your fiscal domicile postal code (5 digits)Example: "06000"

Series and Folio

serie
string
default:"A"
Invoice series identifier (up to 8 alphanumeric characters)Examples: "A", "FAC", "2024"
Use different series for different purposes (e.g., “A” for retail, “B” for wholesale).
folioActual
number
default:"1"
Current folio number (auto-increments with each invoice)Format: 6-digit padded (e.g., 000001, 000002)
autoIncrement
boolean
default:"true"
Automatically increment folio after successful invoice creation
Full Folio Format: {serie}-{folio} Examples:
  • A-000001
  • FAC-000123
  • 2024-001500

CFDI Defaults

Uso de CFDI (Customer Use)

usoCFDI
string
default:"G03"
How the customer will use the invoiceCommon values:
  • G01: Adquisicion de mercancias
  • G02: Devoluciones, descuentos o bonificaciones
  • G03: Gastos en general (most common for retail)
  • I01: Construcciones
  • I02: Mobilario y equipo de oficina por inversiones
  • I03: Equipo de transporte
  • S01: Sin efectos fiscales
Full SAT Catalog c_UsoCFDI

Payment Method (Metodo de Pago)

metodoPago
string
default:"PUE"
Payment timing
  • PUE: Pago en Una sola Exhibicion (single payment)
  • PPD: Pago en Parcialidades o Diferido (installment payments)
Use PUE for immediate payments, PPD for credit sales requiring payment complements.

Payment Form (Forma de Pago)

formaPago
string
default:"01"
Payment instrument usedCommon values:
  • 01: Efectivo (cash)
  • 02: Cheque nominativo
  • 03: Transferencia electronica de fondos
  • 04: Tarjeta de credito
  • 28: Tarjeta de debito
  • 99: Por definir (use with PPD method)
Full SAT Catalog c_FormaPago

Customer Requirements

requiereRFCCliente
boolean
default:"true"
Require customer RFC before generating invoice
Legally required for all CFDI. Use XAXX010101000 for general public only when allowed.
requiereCorreoCliente
boolean
default:"false"
Require customer email to send invoice XML and PDF
Highly recommended for customer convenience and record-keeping.

Test Mode

timbradoPruebas
boolean
default:"true"
Enable test/sandbox modeWhen enabled:
  • Invoices are not legally valid
  • No real stamping/timbrado occurs
  • No charges from PAC
  • Testing CFDI generation workflow
Disable in production to issue legally valid invoices.

PAC Integration

What is a PAC?

A PAC (Proveedor Autorizado de Certificacion) is an SAT-authorized provider that validates and stamps (timbra) your CFDI with the official SAT seal. Popular PAC providers:
  • Finkok
  • SW Sapien
  • Facturomatic
  • Grupo Edicom
  • Paquetexpress

Setup Process

1

Choose a PAC Provider

Research and select a PAC provider based on:
  • Pricing per stamp
  • API quality and documentation
  • Support and reliability
  • Integration options
2

Register and Get Credentials

Sign up with your chosen PAC and obtain:
  • API endpoint URLs
  • Authentication credentials (API key, username/password)
  • Testing/sandbox credentials
3

Install PAC SDK or Library

Many PACs provide SDKs for Node.js:
npm install @finkok/sdk
# or
npm install sw-sapien-sdk
4

Configure Environment Variables

Add PAC credentials to your environment:
# In your .env file (never commit this!)
PAC_API_URL=https://api.pac-provider.com
PAC_API_KEY=your-api-key
PAC_USERNAME=your-username
PAC_PASSWORD=your-password
For Firebase Functions:
firebase functions:config:set \
  pac.api_url="https://api.pac-provider.com" \
  pac.api_key="your-api-key" \
  pac.username="your-username" \
  pac.password="your-password"
5

Implement Stamping Function

Create a Cloud Function to handle CFDI stamping:
functions/src/cfdiStamping.ts
import { onCall } from "firebase-functions/v2/https";
import * as admin from "firebase-admin";
// Import your PAC SDK

export const stampCFDI = onCall(async (request) => {
  const { cfdiXml, issuerRFC } = request.data;

  // Validate request
  if (!request.auth) {
    throw new Error("Authentication required");
  }

  try {
    // Call PAC API to stamp CFDI
    const response = await pacProvider.stamp({
      xml: cfdiXml,
      rfc: issuerRFC
    });

    // Store stamped CFDI in Firestore
    await admin.firestore()
      .collection('facturas')
      .add({
        folio: response.folio,
        uuid: response.uuid,
        xml: response.stampedXml,
        pdf: response.pdfUrl,
        createdAt: admin.firestore.FieldValue.serverTimestamp()
      });

    return {
      success: true,
      uuid: response.uuid,
      stampedXml: response.stampedXml,
      pdfUrl: response.pdfUrl
    };
  } catch (error) {
    console.error('PAC stamping error:', error);
    throw new Error('Failed to stamp CFDI');
  }
});

CFDI Generation Flow

1

Collect Invoice Data

From POS transaction:
  • Issuer information (from config)
  • Customer RFC and name
  • Line items (products/services)
  • Taxes (IVA)
  • Payment method and form
  • Uso de CFDI
2

Build CFDI XML

Generate XML according to SAT CFDI 4.0 schema:
<?xml version="1.0" encoding="UTF-8"?>
<cfdi:Comprobante
  xmlns:cfdi="http://www.sat.gob.mx/cfd/4"
  Version="4.0"
  Serie="A"
  Folio="000001"
  Fecha="2024-03-06T15:30:00"
  FormaPago="01"
  MetodoPago="PUE"
  TipoDeComprobante="I"
  Exportacion="01"
  LugarExpedicion="06000"
  SubTotal="1000.00"
  Total="1160.00">
  
  <cfdi:Emisor
    Rfc="ABC123456D01"
    Nombre="Luis IT Repair"
    RegimenFiscal="626"/>
  
  <cfdi:Receptor
    Rfc="XAXX010101000"
    Nombre="Cliente General"
    DomicilioFiscalReceptor="06000"
    RegimenFiscalReceptor="616"
    UsoCFDI="G03"/>
  
  <cfdi:Conceptos>
    <cfdi:Concepto
      ClaveProdServ="43211500"
      Cantidad="1"
      ClaveUnidad="E48"
      Descripcion="Reparacion de laptop"
      ValorUnitario="1000.00"
      Importe="1000.00"
      ObjetoImp="02">
      
      <cfdi:Impuestos>
        <cfdi:Traslados>
          <cfdi:Traslado
            Base="1000.00"
            Impuesto="002"
            TipoFactor="Tasa"
            TasaOCuota="0.160000"
            Importe="160.00"/>
        </cfdi:Traslados>
      </cfdi:Impuestos>
    </cfdi:Concepto>
  </cfdi:Conceptos>
  
  <cfdi:Impuestos
    TotalImpuestosTrasladados="160.00">
    <cfdi:Traslados>
      <cfdi:Traslado
        Base="1000.00"
        Impuesto="002"
        TipoFactor="Tasa"
        TasaOCuota="0.160000"
        Importe="160.00"/>
    </cfdi:Traslados>
  </cfdi:Impuestos>
</cfdi:Comprobante>
3

Sign XML with CSD

Apply your digital certificate (Certificado de Sello Digital):
  • Load .cer and .key files
  • Generate cryptographic seal
  • Add seal to XML
4

Send to PAC for Stamping

Submit signed XML to PAC API for validation and stamping.
5

Receive Stamped CFDI

PAC returns:
  • UUID (Folio Fiscal) - Unique SAT identifier
  • Timbre Fiscal Digital (SAT stamp)
  • Stamped XML with complete CFDI
  • Optional: PDF representation
6

Store and Deliver

  • Save to Firestore (facturas collection)
  • Send XML and PDF to customer via email
  • Print confirmation receipt
  • Update folio counter

SAT Catalogs

Common Catalog Codes

{
  "43211500": "Computer repair and maintenance services",
  "43211501": "Computer hardware installation services",
  "43211503": "Software installation services",
  "43211902": "Data recovery services",
  "43222600": "Software licensing services",
  "81112100": "Computer accessories",
  "81161700": "Data cables"
}
Full SAT Catalog Codes

Cancellation and Credits

Cancel Invoice

To cancel a CFDI:
1

Request Cancellation from PAC

Call PAC API with UUID to cancel:
const result = await pacProvider.cancelCFDI({
  uuid: 'ABC12345-6789-...',
  rfc: 'ABC123456D01',
  motive: '01', // Comprobante emitido con errores
  replacementUuid: null // Optional replacement UUID
});
2

Update Firestore Record

Mark invoice as cancelled:
await admin.firestore()
  .collection('facturas')
  .doc(invoiceId)
  .update({
    status: 'cancelled',
    cancelledAt: admin.firestore.FieldValue.serverTimestamp(),
    cancellationMotive: '01'
  });
3

Notify Customer

Send cancellation notification via email.

Credit Notes (Egreso)

For returns or corrections, create a credit note (Egreso CFDI):
<cfdi:Comprobante
  TipoDeComprobante="E"
  ...>
  <!-- References original invoice -->
</cfdi:Comprobante>

Compliance and Best Practices

For legal compliance, always request customer RFC when issuing invoices. Only use “XAXX010101000” (general public) when legally allowed.
SAT requires you to keep XML files for 5 years. Implement automatic backup to cloud storage:
import { getStorage } from "firebase-admin/storage";

const bucket = getStorage().bucket();
await bucket.file(`facturas/${uuid}.xml`).save(stampedXml);
Track your PAC credit balance to avoid service interruptions.
Always test CFDI generation in PAC sandbox before going live.
Use SAT’s official XSD schemas to validate XML before sending to PAC.
SAT rules allow easier cancellation within 72 hours of issuance.

Troubleshooting

Common causes:
  • Invalid RFC format
  • Incorrect catalog codes
  • Missing required fields
  • XML schema validation errors
  • Math errors in totals/taxes
Check PAC error response for specific validation failure.
  • Verify .cer and .key files are valid and not expired
  • Ensure CSD password is correct
  • Check that RFC in certificate matches configuration
  • Verify PAC credentials are correct
  • Check PAC service status
  • Ensure you have sufficient PAC credits
  • Review PAC API logs
Customers can validate invoices at: https://verificacfdi.facturaelectronica.sat.gob.mx/They need:
  • UUID
  • Issuer RFC
  • Receiver RFC
  • Total amount

Resources

SAT CFDI Portal

Official SAT documentation and catalogs

SAT Schemas

XML Schema Definition (XSD) files

CFDI Validator

Validate issued invoices

Authorized PAC List

SAT-authorized PAC providers

Next Steps

POS Settings

Configure IVA and ticket printing

Firebase Functions

Deploy billing functions

Build docs developers (and LLMs) love