POST /cfdi/timbrar-nomina genera, sella y timbra un CFDI 4.0 tipo N (recibo de nómina)
con el complemento Nómina 1.2 del SAT. Emites un recibo por empleado y por periodo de pago.
Es un endpoint distinto de POST /cfdi/timbrar porque el cuerpo es distinto: no envías
conceptos, subtotal ni total. Envías las percepciones, deducciones y otros pagos del
periodo y los datos del empleado, y Ipsofactura arma el comprobante completo con la
estructura que exige la guía de llenado del SAT.
La referencia campo por campo está en
POST /cfdi/timbrar-nomina, generada
directamente del código de la API. Esta guía explica las reglas que la referencia no puede
expresar.Qué arma Ipsofactura por ti
Un CFDI de nómina tiene casi todos los atributos del comprobante fijos por norma. No los envías y no son configurables:
Los totales del comprobante se calculan a partir de tus totales del complemento:
rfc, nombre y domicilio_fiscal (código postal). El régimen y el
uso de CFDI los fija el endpoint. serie, folio, fecha y lugar_expedicion siguen los
mismos defaults que POST /cfdi/timbrar.
Ejemplo: nómina ordinaria de sueldos
Una quincena de un empleado bajo régimen de sueldos (tipo_regimen 02), con ISR retenido y
subsidio para el empleo:
Request
Response 201
nomina12:Nomina completo, se descarga con GET /cfdi/{id}/xml.
Los totales deben cuadrar con el detalle
Los tres totales son obligatorios, incluso en cero, y cada uno debe ser exactamente la suma de su detalle. Si no coinciden, la respuesta es400 NOMINA_TOTALS_MISMATCH y no se consume
timbre:
400 NOMINA_TOTALS_MISMATCH
Qué validamos antes de llamar al PAC
Todo lo que sigue responde400 VALIDATION_ERROR con el nombre del campo en message, sin
consumir timbre. Son las reglas de la guía de llenado y de la matriz de errores de nómina del
SAT que dependen sólo del payload.
Periodo y días
fecha_inicial_pago≤fecha_final_pago, yfecha_pago≥fecha_inicial_pago.num_dias_pagados> 0. Acepta fracción:7.5se timbra como7.500(el SAT exige entero o exactamente tres decimales; nosotros hacemos la conversión).
Empleado
El bloque del registro patronal va completo o no va. Si envías
empleador.registro_patronal, son obligatorios num_seguridad_social,
fecha_inicio_rel_laboral, antiguedad (si la omites la calculamos, ver abajo), riesgo_puesto
y salario_diario_integrado. Si no lo envías, ninguno de esos cinco debe aparecer. Es una regla literal de la guía de llenado; en la
práctica una nómina de sueldos (contrato 01 a 08) siempre lleva registro patronal y el
bloque completo, y una de asimilados a salarios (tipo_regimen 09, contrato 99) no lleva
ninguno.
El tipo de contrato decide el régimen y si hay registro patronal. Con tipo_contrato 01 a
08 (una relación laboral), tipo_regimen debe ser 02, 03 o 04 y
empleador.registro_patronal es obligatorio. Con 09, 10 o 99, tipo_regimen va de 05 a
99 y el registro patronal no debe venir.
La periodicidad sigue al tipo de nómina, no al régimen. Una nómina ordinaria (O) no admite
periodicidad_pago 99; una extraordinaria (E) la exige.
antiguedad la calculamos si la omites. Cuando hay registro patronal y no envías
antiguedad, la calculamos como el lapso en años, meses y días entre fecha_inicio_rel_laboral
y fecha_final_pago: del 2020-03-01 al 2026-09-15, P6Y6M14D. Si la envías, la respetamos
tal cual, y el SAT la rechaza con NOM55 si no es ese lapso. fecha_inicio_rel_laboral no puede
ser posterior a fecha_final_pago.
Catálogos
Cualquier clave fuera del catálogo del SAT responde400 con la lista de valores aceptados en
message. No la degradamos ni la enviamos al PAC.
La
clave de cada percepción, deducción y otro pago es tu clave interna. El SAT la exige de
3 a 15 caracteres: una clave interna de uno o dos caracteres (1, P1) se rechaza con
400. Si tu catálogo interno usa claves cortas, rellénalas (001, P01).
Horas extra
horas_extra cuelga de la percepción que las paga, y el SAT sólo lo admite bajo
tipo_percepcion 019. Enviarlo en cualquier otra percepción es 400.
Percepción 019 con horas extra
Otros pagos y el subsidio para el empleo
Es la regla que más nóminas rechaza, así que va primero: en una nómina de sueldos (tipo_regimen 02) el SAT exige un otro pago con tipo_otro_pago 002 (subsidio para el
empleo), aunque el subsidio sea cero, salvo que la nómina traiga un 007 (ISR ajustado por
subsidio) o un 008 (subsidio entregado que no correspondía). Sin esa línea el SAT responde
NOM105. Validamos esto antes de timbrar.
Subsidio causado pero no entregado (importe en cero)
subsidio_causado no es lo mismo que importe: importe es lo que le entregaste al
empleado y subsidio_causado lo que le corresponde según la tabla del subsidio vigente. El SAT
compara ambos. Los topes de esa tabla (NOM101, NOM108) cambian cada año con la Resolución
Miscelánea, así que no los validamos nosotros: los aplica el SAT al timbrar.
Finiquitos, indemnizaciones y jubilación
Un finiquito o una liquidación se timbra como cualquier otro recibo: sus percepciones van enpercepciones[] junto con el sueldo del último periodo. Normalmente es una nómina
extraordinaria (tipo_nomina E, periodicidad_pago 99). Lo que cambia es que ciertas
claves de percepción exigen un bloque de datos adicional:
Cada bloque va una vez por recibo, dentro de
nomina, no dentro de cada percepción: describe
el total de esas percepciones aunque las separes en varias líneas.
Como toda nómina extraordinaria, un finiquito lleva periodicidad_pago 99.
Los subtotales de percepciones los calculamos nosotros por clave: el sueldo por un lado, la
separación por otro y la jubilación por otro. Tú sólo mandas total_percepciones, que sigue
siendo la suma de todas las percepciones.
Finiquito: último sueldo, prima de antigüedad e indemnización
separacion_indemnizacion los cinco campos son obligatorios y num_anios_servicio va de
0 a 99. ingreso_acumulable e ingreso_no_acumulable los determina tu sistema de nómina
conforme a la guía de llenado del SAT; nosotros los transportamos sin recalcularlos.
Una jubilación se paga en una exhibición o en parcialidades, nunca de las dos formas:
En los dos casos,
ingreso_acumulable e ingreso_no_acumulable son obligatorios.
Pensión en parcialidades (044)
400 antes de timbrar:
Para un jubilado usa
tipo_regimen 03: no lleva subsidio para el empleo, que es sólo para
02 (ver la sección anterior).
Lo que valida el SAT y nosotros no
Estas reglas dependen de datos que no están en tu payload (el padrón del SAT, la relación laboral, las tablas fiscales). Llegan como400 VALIDATION_ERROR después de llamar al PAC,
sin consumir timbre, con el código del SAT (NOMxx) en sat_code:
Rechazo del SAT en nómina
Cobertura actual
Timbra hoy, verificado contra el ambiente de pruebas del PAC:- Nómina ordinaria y extraordinaria (
tipo_nominaO/E). - Régimen de sueldos (
02) con subsidio para el empleo, y asimilados a salarios (09). - Percepciones con horas extra (
019), incapacidades, otros pagos con subsidio al empleo (002) y compensación de saldos a favor (004). - Nómina sin deducciones, y días pagados fraccionarios.
- Finiquitos: separación e indemnización (
022,023,025), y jubilación, pensión o retiro en una exhibición (039) o en parcialidades (044). Ver la sección Finiquitos, indemnizaciones y jubilación.
- Percepción
045(acciones o títulos) y subcontratación (SubContratacionen el receptor). GET /cfdi/{id}devuelve el comprobante (un concepto “Pago de nómina”) pero no el detalle del complemento. Para leer percepciones y deducciones de un recibo ya timbrado descarga el XML conGET /cfdi/{id}/xml.
GET /cfdi/{id}/pdf de un tipo N devuelve un recibo de nómina: patrón y empleado, periodo y
días pagados, percepciones, deducciones, otros pagos e incapacidades, el neto a pagar y el timbre
con su QR. El PDF se genera una vez y se conserva, así que un recibo cuyo PDF pediste antes de
que existiera esta plantilla sigue entregando el documento original.
Idempotencia, reintentos y cancelación
Se comportan igual que enPOST /cfdi/timbrar:
- Reenviar el mismo
idempotency_keycon el mismo payload devuelve el primer resultado; la mismaserie+foliofunciona igual. Ver Recuperación tras timeout. - Una clave estable natural es
nomina-<num_empleado>-<periodo>. - La nómina se timbra únicamente por el PAC que acepta el complemento Nómina 1.2, así que no
tiene el respaldo de un segundo PAC: si ese proveedor no está disponible recibes
503y debes reintentar con la misma clave. - Un recibo se cancela con
POST /cfdi/cancelarcomo cualquier CFDI. Ver Cancelación. - El webhook
cfdi.timbradose dispara igual que para cualquier comprobante. Ver Webhooks.
En el sandbox
El sandbox responde201 con un UUID simulado y aplica todas las validaciones
de esta guía que dependen del payload: totales, catálogos, periodo, CURP, bloque del registro
patronal y reglas de otros pagos. Úsalo para probar el contrato de la API y tu manejo de errores.
Lo que no puedes verificar ahí:
- Las reglas del SAT de la sección anterior (
NOM55,NOM34,NOM42, identidad del receptor contra el padrón): el sandbox no las aplica.
nomina12:Nomina
completo, con la misma estructura que el de producción, así que puedes validar tu parser y la
estructura del complemento contra el XSD del SAT desde el sandbox. El sello y el timbre son
simulados y no tienen validez fiscal.