Skip to main content

POST /api/invoices/upload

Uploads and processes a CFDI XML file (invoice or expense), performs fiscal validations, and saves it to the database.

Authentication

Requires Bearer token authentication. The token must be included in the Authorization header.

Rate Limiting

  • Limit: 300 requests per 5 minutes per user
  • Error Message: “Demasiadas solicitudes para procesar XML. Intenta nuevamente en unos minutos.”

Request

xml
file
required
XML file containing the CFDI invoice. Must have .xml extension.
profileId
string
required
UUID of the profile to associate the invoice with. The profile must belong to the authenticated user.

Validation Rules

  • File must have .xml extension
  • Profile must belong to authenticated user
  • RFC must match profile (either as emisor or receptor)
  • UUID must not be duplicated in the database
  • Fiscal regime validation (if enabled in profile settings)
  • For PPD invoices: applies existing payment complements automatically

Response

message
string
Success message: “Factura guardada exitosamente” or “Gasto guardado exitosamente”
data
object
The saved invoice or expense record
id
string
UUID of the saved record
profile_id
string
UUID of the associated profile
uuid
string
Fiscal UUID from the CFDI
fecha
string
Invoice date (ISO 8601 format)
mes
number
Month (1-12)
año
number
Year
total
number
Total amount including taxes
subtotal
number
Subtotal before taxes
iva
number
IVA amount
iva_amount
number
Transferred IVA amount
retencion_iva_amount
number
IVA withholding amount
retencion_isr_amount
number
ISR withholding amount
tipo
string
Payment type: “PUE” (paid in one payment), “PPD” (paid in installments), or “COMPLEMENTO_PAGO” (payment complement)
rfc_emisor
string
RFC of the issuer
nombre_emisor
string
Name of the issuer
regimen_fiscal_emisor
string
Fiscal regime code of the issuer (3-digit SAT code)
rfc_receptor
string
RFC of the recipient
nombre_receptor
string
Name of the recipient
regimen_fiscal_receptor
string
Fiscal regime code of the recipient
concepto
string
Description or concept of the invoice
pagos
array
Array of partial payments (for PPD invoices)
complemento_pago
object
Payment complement data (if applicable)
validacion
object
Validation results
rfcVerificado
boolean
Whether RFC was verified
regimenFiscalVerificado
boolean
Whether fiscal regime was verified
uuidDuplicado
boolean
Whether UUID is duplicated
advertencias
array
Array of validation warnings
errores
array
Array of validation errors
valido
boolean
Whether the invoice passed all validations
estadoPago
object
Payment status information
estado
string
Payment state: “PAGADO”, “PAGO_PARCIAL”, or “NO_PAGADO”
totalFactura
number
Total invoice amount
totalPagado
number
Total amount paid
saldoPendiente
number
Outstanding balance
porcentajePagado
number
Percentage paid (0-100)
completamentePagado
boolean
Whether the invoice is fully paid
tieneComplementos
boolean
Whether payment complements exist
tienePagosManuales
boolean
Whether manual payments exist
validacion
object
Validation state (same structure as above)
tipo
string
Record type: “factura” (invoice) or “gasto” (expense)

Error Codes

400
error
Bad Request
  • Missing or invalid profileId
  • No XML file provided
  • File is not XML format
  • CFDI doesn’t correspond to the profile
  • CFDI failed fiscal validations
401
error
Unauthorized - User not authenticated
404
error
Not Found - Profile not found or doesn’t belong to user
409
error
Conflict - UUID already exists in database (duplicate CFDI)
429
error
Too Many Requests - Rate limit exceeded (300 requests per 5 minutes)
500
error
Internal Server Error - Unexpected error processing XML

Example Request

curl -X POST https://api.tresacontafy.com/api/invoices/upload \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -F "[email protected]" \
  -F "profileId=550e8400-e29b-41d4-a716-446655440000"

Example Response (Success)

{
  "message": "Factura guardada exitosamente",
  "data": {
    "id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
    "profile_id": "550e8400-e29b-41d4-a716-446655440000",
    "uuid": "12345678-1234-1234-1234-123456789012",
    "fecha": "2024-03-15T10:30:00.000Z",
    "mes": 3,
    "año": 2024,
    "total": 11600.00,
    "subtotal": 10000.00,
    "iva": 1600.00,
    "iva_amount": 1600.00,
    "retencion_iva_amount": 0.00,
    "retencion_isr_amount": 0.00,
    "tipo": "PUE",
    "rfc_emisor": "ABC123456789",
    "nombre_emisor": "Empresa Ejemplo SA de CV",
    "regimen_fiscal_emisor": "612",
    "rfc_receptor": "XYZ987654321",
    "nombre_receptor": "Cliente Ejemplo",
    "regimen_fiscal_receptor": "605",
    "concepto": "Servicios de consultoría",
    "pagos": [],
    "complemento_pago": null,
    "validacion": {
      "rfcVerificado": true,
      "regimenFiscalVerificado": true,
      "uuidDuplicado": false,
      "advertencias": [],
      "errores": [],
      "valido": true
    },
    "created_at": "2024-03-15T10:35:00.000Z",
    "updated_at": "2024-03-15T10:35:00.000Z"
  },
  "estadoPago": {
    "estado": "PAGADO",
    "totalFactura": 11600.00,
    "totalPagado": 11600.00,
    "saldoPendiente": 0.00,
    "porcentajePagado": 100,
    "completamentePagado": true,
    "tieneComplementos": false,
    "tienePagosManuales": false
  },
  "validacion": {
    "rfcVerificado": true,
    "regimenFiscalVerificado": true,
    "uuidDuplicado": false,
    "advertencias": [],
    "errores": [],
    "valido": true
  },
  "tipo": "factura"
}

Example Response (Error - Duplicate)

{
  "error": "El CFDI ya existe en la base de datos",
  "message": "El uuid (12345678-1234-1234-1234-123456789012) ya fue procesado anteriormente",
  "field": "uuid",
  "value": "12345678-1234-1234-1234-123456789012"
}

Example Response (Error - Validation Failed)

{
  "error": "El CFDI no pasó las validaciones fiscales",
  "validacion": {
    "rfcVerificado": false,
    "regimenFiscalVerificado": true,
    "uuidDuplicado": false,
    "advertencias": [],
    "errores": [
      "El RFC del emisor no coincide con el perfil"
    ],
    "valido": false
  },
  "data": {
    "uuid": "12345678-1234-1234-1234-123456789012",
    "fecha": "2024-03-15T10:30:00.000Z",
    "tipo": "PUE",
    "total": 11600.00
  }
}

Notes

  • The endpoint automatically determines if the CFDI is an invoice (ingreso) or expense (gasto) based on whether the profile’s RFC matches the emisor or receptor
  • For PPD (installment payment) invoices, the system automatically applies any existing payment complements
  • Payment complements (COMPLEMENTO_PAGO) are processed but not saved as invoices/expenses - they are used to update payment status of related invoices
  • Validation rules can be customized per profile using the validaciones_habilitadas configuration

Build docs developers (and LLMs) love