# Nómina

> Dé de alta a sus empleados y timbre sus recibos de nómina ordinaria (CFDI tipo N con Nómina 1.2): el ISR, el subsidio para el empleo y las cuotas del IMSS los calcula Fiscalisto.

Un **recibo de nómina** es un CFDI de tipo N con el complemento Nómina 1.2. Usted manda el empleado y el periodo; Fiscalisto calcula el sueldo de los días pagados, el ISR con la tarifa del artículo 96 y el subsidio para el empleo vigente, y las cuotas obreras del IMSS, como **Nómina › Emitir recibos** en la app. Nunca timbra montos que usted escriba a mano, así que un recibo siempre cuadra con lo que pide el SAT.

Cada recibo usa un timbre, como cualquier factura. En pruebas se timbra con los emisores de prueba del SAT, sin costo.

## Antes del primer recibo

El emisor necesita su **registro patronal** del IMSS (11 caracteres) y, si es persona física, su CURP:

```bash tab="cURL"
curl https://api.fiscalisto.com/v1/issuers/iss_OufpKqnrvx9p \
  -H "Authorization: Bearer $FISCALISTO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "employer_registration": "Y5412345109" }'
```

```ts tab="TypeScript"
import { Fiscalisto } from "fiscalisto";

// La llave viene de FISCALISTO_API_KEY.
const fiscalisto = new Fiscalisto();

const issuer = await fiscalisto.issuers.update("iss_OufpKqnrvx9p", { employer_registration: "Y5412345109" });
```

```python tab="Python"
from fiscalisto import Fiscalisto

# La llave viene de FISCALISTO_API_KEY.
fiscalisto = Fiscalisto()

issuer = fiscalisto.issuers.update("iss_OufpKqnrvx9p", {"employer_registration": "Y5412345109"})
```

```php tab="PHP"
<?php

use Fiscalisto\Fiscalisto;

// La llave viene de FISCALISTO_API_KEY.
$fiscalisto = new Fiscalisto();

$issuer = $fiscalisto->issuers->update('iss_OufpKqnrvx9p', ['employer_registration' => 'Y5412345109']);
```

```go tab="Go"
package main

import (
	"context"
	"fmt"
	"log"

	fiscalisto "fiscalisto.com/go"
)

func main() {
	// La llave viene de FISCALISTO_API_KEY.
	client, err := fiscalisto.NewClient("")
	if err != nil {
		log.Fatal(err)
	}
	ctx := context.Background()

	issuer, err := client.Issuers.Update(ctx, "iss_OufpKqnrvx9p", &fiscalisto.UpdateIssuerParams{
		EmployerRegistration: fiscalisto.String("Y5412345109"),
	})
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(issuer.ID)
}
```

```java tab="Java"
import com.fiscalisto.FiscalistoClient;
import com.fiscalisto.model.UpdateIssuerParams;

// La llave viene de FISCALISTO_API_KEY.
var fiscalisto = new FiscalistoClient();

var issuer = fiscalisto.issuers().update("iss_OufpKqnrvx9p", new UpdateIssuerParams().setEmployerRegistration("Y5412345109"));
System.out.println(issuer.getId());
```

```csharp tab="C#"
using Fiscalisto;

// La llave viene de FISCALISTO_API_KEY.
var fiscalisto = new FiscalistoClient();

var issuer = await fiscalisto.Issuers.UpdateAsync("iss_OufpKqnrvx9p", new UpdateIssuerParams
{
    EmployerRegistration = "Y5412345109",
});
```

Sin él, un recibo contesta `422` `payroll_invalid` y lo dice.

## Dar de alta un empleado

```bash tab="cURL"
curl https://api.fiscalisto.com/v1/employees \
  -H "Authorization: Bearer $FISCALISTO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "number": "9",
    "name": "Ana Gómez Ruiz",
    "tax_id": "GORA800101AB1",
    "curp": "GORA800101MDFMZN09",
    "social_security_number": "12345678903",
    "zip": "06000",
    "email": "ana@example.com",
    "start_date": "2024-03-04",
    "daily_salary": 320,
    "integrated_daily_salary": 334.66,
    "periodicity": "04",
    "state": "CMX"
  }'
```

```ts tab="TypeScript"
import { Fiscalisto } from "fiscalisto";

// La llave viene de FISCALISTO_API_KEY.
const fiscalisto = new Fiscalisto();

const employee = await fiscalisto.employees.create({
  number: "9",
  name: "Ana Gómez Ruiz",
  tax_id: "GORA800101AB1",
  curp: "GORA800101MDFMZN09",
  social_security_number: "12345678903",
  zip: "06000",
  email: "ana@example.com",
  start_date: "2024-03-04",
  daily_salary: 320,
  integrated_daily_salary: 334.66,
  periodicity: "04",
  state: "CMX",
});
```

```python tab="Python"
from fiscalisto import Fiscalisto

# La llave viene de FISCALISTO_API_KEY.
fiscalisto = Fiscalisto()

employee = fiscalisto.employees.create({
    "number": "9",
    "name": "Ana Gómez Ruiz",
    "tax_id": "GORA800101AB1",
    "curp": "GORA800101MDFMZN09",
    "social_security_number": "12345678903",
    "zip": "06000",
    "email": "ana@example.com",
    "start_date": "2024-03-04",
    "daily_salary": 320,
    "integrated_daily_salary": 334.66,
    "periodicity": "04",
    "state": "CMX",
})
```

```php tab="PHP"
<?php

use Fiscalisto\Fiscalisto;

// La llave viene de FISCALISTO_API_KEY.
$fiscalisto = new Fiscalisto();

$employee = $fiscalisto->employees->create([
    'number' => '9',
    'name' => 'Ana Gómez Ruiz',
    'tax_id' => 'GORA800101AB1',
    'curp' => 'GORA800101MDFMZN09',
    'social_security_number' => '12345678903',
    'zip' => '06000',
    'email' => 'ana@example.com',
    'start_date' => '2024-03-04',
    'daily_salary' => 320,
    'integrated_daily_salary' => 334.66,
    'periodicity' => '04',
    'state' => 'CMX',
]);
```

```go tab="Go"
package main

import (
	"context"
	"fmt"
	"log"

	fiscalisto "fiscalisto.com/go"
)

func main() {
	// La llave viene de FISCALISTO_API_KEY.
	client, err := fiscalisto.NewClient("")
	if err != nil {
		log.Fatal(err)
	}
	ctx := context.Background()

	employee, err := client.Employees.Create(ctx, &fiscalisto.CreateEmployeeParams{
		Number:                "9",
		Name:                  "Ana Gómez Ruiz",
		TaxID:                 "GORA800101AB1",
		CURP:                  "GORA800101MDFMZN09",
		SocialSecurityNumber:  "12345678903",
		Zip:                   "06000",
		Email:                 fiscalisto.String("ana@example.com"),
		StartDate:             "2024-03-04",
		DailySalary:           320,
		IntegratedDailySalary: 334.66,
		Periodicity:           fiscalisto.String("04"),
		State:                 "CMX",
	})
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(employee.ID)
}
```

```java tab="Java"
import com.fiscalisto.FiscalistoClient;
import com.fiscalisto.model.CreateEmployeeParams;

// La llave viene de FISCALISTO_API_KEY.
var fiscalisto = new FiscalistoClient();

var employee = fiscalisto.employees().create(new CreateEmployeeParams()
        .setNumber("9")
        .setName("Ana Gómez Ruiz")
        .setTaxId("GORA800101AB1")
        .setCurp("GORA800101MDFMZN09")
        .setSocialSecurityNumber("12345678903")
        .setZip("06000")
        .setEmail("ana@example.com")
        .setStartDate("2024-03-04")
        .setDailySalary(320)
        .setIntegratedDailySalary(334.66)
        .setPeriodicity("04")
        .setState("CMX"));
System.out.println(employee.getId());
```

```csharp tab="C#"
using Fiscalisto;

// La llave viene de FISCALISTO_API_KEY.
var fiscalisto = new FiscalistoClient();

var employee = await fiscalisto.Employees.CreateAsync(new CreateEmployeeParams
{
    Number = "9",
    Name = "Ana Gómez Ruiz",
    TaxId = "GORA800101AB1",
    Curp = "GORA800101MDFMZN09",
    SocialSecurityNumber = "12345678903",
    Zip = "06000",
    Email = "ana@example.com",
    StartDate = "2024-03-04",
    DailySalary = 320,
    IntegratedDailySalary = 334.66m,
    Periodicity = "04",
    State = "CMX",
});
```

El nombre, el RFC y el código postal van como en la constancia de situación fiscal del empleado: el SAT los compara. Lo que no mande tiene el valor usual de **Nuevo empleado**:

| Campo | Por omisión | Qué es |
| --- | --- | --- |
| `contract_type` | `01` | Contrato por tiempo indeterminado (c_TipoContrato). |
| `workday_type` | `01` | Jornada diurna (c_TipoJornada). |
| `periodicity` | `04` | Quincenal. También `02` semanal, `03` catorcenal y `05` mensual. |
| `risk_class` | `1` | Clase de riesgo del puesto ante el IMSS, de 1 a 5. |
| `border_zone` | `false` | Si trabaja en la zona libre de la frontera norte (salario mínimo de la zona). |

La respuesta trae `warnings` con lo que el SAT podría rechazar antes de timbrar, por ejemplo un RFC o una CURP cuyo dígito verificador no corresponde. No impiden guardarlo: revíselos con el empleado.

Un RFC o un número de empleado que ya existe en el emisor contesta `400` `employee_exists`. Para cambiar un salario o dar de baja (`end_date`), use [`POST /v1/employees/{id}`](https://fiscalisto.com/docs/api/referencia/nomina/update-employee) con solo lo que cambia; los recibos ya timbrados no cambian.

## Ver el recibo antes de timbrarlo

```bash tab="cURL"
curl https://api.fiscalisto.com/v1/payroll_receipts/preview \
  -H "Authorization: Bearer $FISCALISTO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "employee": "emp_OufpKqnrvx9p4gtWHOcPMsq25QUp6Licjr",
    "period": { "start": "2026-10-01", "end": "2026-10-15" }
  }'
```

```ts tab="TypeScript"
import { Fiscalisto } from "fiscalisto";

// La llave viene de FISCALISTO_API_KEY.
const fiscalisto = new Fiscalisto();

const payrollReceiptPreview = await fiscalisto.payrollReceipts.preview({
  employee: "emp_OufpKqnrvx9p4gtWHOcPMsq25QUp6Licjr",
  period: { start: "2026-10-01", end: "2026-10-15" },
});
```

```python tab="Python"
from fiscalisto import Fiscalisto

# La llave viene de FISCALISTO_API_KEY.
fiscalisto = Fiscalisto()

payroll_receipt_preview = fiscalisto.payroll_receipts.preview({
    "employee": "emp_OufpKqnrvx9p4gtWHOcPMsq25QUp6Licjr",
    "period": {"start": "2026-10-01", "end": "2026-10-15"},
})
```

```php tab="PHP"
<?php

use Fiscalisto\Fiscalisto;

// La llave viene de FISCALISTO_API_KEY.
$fiscalisto = new Fiscalisto();

$payrollReceiptPreview = $fiscalisto->payrollReceipts->preview([
    'employee' => 'emp_OufpKqnrvx9p4gtWHOcPMsq25QUp6Licjr',
    'period' => [
        'start' => '2026-10-01',
        'end' => '2026-10-15',
    ],
]);
```

```go tab="Go"
package main

import (
	"context"
	"fmt"
	"log"

	fiscalisto "fiscalisto.com/go"
)

func main() {
	// La llave viene de FISCALISTO_API_KEY.
	client, err := fiscalisto.NewClient("")
	if err != nil {
		log.Fatal(err)
	}
	ctx := context.Background()

	payrollReceiptPreview, err := client.PayrollReceipts.Preview(ctx, &fiscalisto.PreviewPayrollReceiptParams{
		Employee: "emp_OufpKqnrvx9p4gtWHOcPMsq25QUp6Licjr",
		Period: fiscalisto.PreviewPayrollReceiptParamsPeriod{
			Start: "2026-10-01",
			End:   "2026-10-15",
		},
	})
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("%+v\n", *payrollReceiptPreview)
}
```

```java tab="Java"
import com.fiscalisto.FiscalistoClient;
import com.fiscalisto.model.PreviewPayrollReceiptParams;
import com.fiscalisto.model.PreviewPayrollReceiptParamsPeriod;

// La llave viene de FISCALISTO_API_KEY.
var fiscalisto = new FiscalistoClient();

var payrollReceiptPreview = fiscalisto.payrollReceipts().preview(new PreviewPayrollReceiptParams()
        .setEmployee("emp_OufpKqnrvx9p4gtWHOcPMsq25QUp6Licjr")
        .setPeriod(new PreviewPayrollReceiptParamsPeriod()
                .setStart("2026-10-01")
                .setEnd("2026-10-15")));
System.out.println(payrollReceiptPreview);
```

```csharp tab="C#"
using Fiscalisto;

// La llave viene de FISCALISTO_API_KEY.
var fiscalisto = new FiscalistoClient();

var payrollReceiptPreview = await fiscalisto.PayrollReceipts.PreviewAsync(new PreviewPayrollReceiptParams
{
    Employee = "emp_OufpKqnrvx9p4gtWHOcPMsq25QUp6Licjr",
    Period = new() { Start = "2026-10-01", End = "2026-10-15" },
});
```

Contesta el recibo como se timbraría, sin timbrar ni usar timbres:

```json
{
  "object": "payroll_receipt_preview",
  "periodicity": "04",
  "period": { "start": "2026-10-01", "end": "2026-10-15", "payment_date": "2026-10-15" },
  "days": 15,
  "perceptions": [{ "type": "001", "key": "001", "concept": "Sueldo", "taxed": 4800, "exempt": 0 }],
  "deductions": [
    { "type": "001", "key": "001", "concept": "Cuotas IMSS", "amount": 119.21 },
    { "type": "002", "key": "002", "concept": "ISR", "amount": 80.85 }
  ],
  "isr": { "tariff": 345.15, "subsidy": 264.3, "withheld": 80.85, "exempt_minimum": false },
  "totals": { "perceptions": 4800, "deductions": 200.06, "net": 4599.94 }
}
```

`isr.tariff` es el ISR de la tarifa, `isr.subsidy` el subsidio para el empleo que le toca y `isr.withheld` lo que se le retiene. El periodo va en hora de la Ciudad de México; `payment_date` (la fecha de pago) es su último día si no la manda, y `days` son todos los días pagables del periodo (sin los anteriores a su ingreso ni los posteriores a su baja). Mande `days` para pagar menos, por ejemplo con faltas.

## Timbrarlo

```bash tab="cURL"
curl https://api.fiscalisto.com/v1/payroll_receipts \
  -H "Authorization: Bearer $FISCALISTO_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: nomina-2026-10-q1-9" \
  -d '{
    "employee": "emp_OufpKqnrvx9p4gtWHOcPMsq25QUp6Licjr",
    "period": { "start": "2026-10-01", "end": "2026-10-15" },
    "send_email": true,
    "metadata": { "corrida": "2026-19" }
  }'
```

```ts tab="TypeScript"
import { Fiscalisto } from "fiscalisto";

// La llave viene de FISCALISTO_API_KEY.
const fiscalisto = new Fiscalisto();

const invoice = await fiscalisto.payrollReceipts.create({
  employee: "emp_OufpKqnrvx9p4gtWHOcPMsq25QUp6Licjr",
  period: { start: "2026-10-01", end: "2026-10-15" },
  send_email: true,
  metadata: { corrida: "2026-19" },
}, { idempotencyKey: "nomina-2026-10-q1-9" });
```

```python tab="Python"
from fiscalisto import Fiscalisto

# La llave viene de FISCALISTO_API_KEY.
fiscalisto = Fiscalisto()

invoice = fiscalisto.payroll_receipts.create({
    "employee": "emp_OufpKqnrvx9p4gtWHOcPMsq25QUp6Licjr",
    "period": {"start": "2026-10-01", "end": "2026-10-15"},
    "send_email": True,
    "metadata": {"corrida": "2026-19"},
}, idempotency_key="nomina-2026-10-q1-9")
```

```php tab="PHP"
<?php

use Fiscalisto\Fiscalisto;

// La llave viene de FISCALISTO_API_KEY.
$fiscalisto = new Fiscalisto();

$invoice = $fiscalisto->payrollReceipts->create([
    'employee' => 'emp_OufpKqnrvx9p4gtWHOcPMsq25QUp6Licjr',
    'period' => [
        'start' => '2026-10-01',
        'end' => '2026-10-15',
    ],
    'send_email' => true,
    'metadata' => ['corrida' => '2026-19'],
], ['idempotency_key' => 'nomina-2026-10-q1-9']);
```

```go tab="Go"
package main

import (
	"context"
	"fmt"
	"log"

	fiscalisto "fiscalisto.com/go"
)

func main() {
	// La llave viene de FISCALISTO_API_KEY.
	client, err := fiscalisto.NewClient("")
	if err != nil {
		log.Fatal(err)
	}
	ctx := context.Background()

	invoice, err := client.PayrollReceipts.Create(ctx, &fiscalisto.CreatePayrollReceiptParams{
		Employee: "emp_OufpKqnrvx9p4gtWHOcPMsq25QUp6Licjr",
		Period: fiscalisto.CreatePayrollReceiptParamsPeriod{
			Start: "2026-10-01",
			End:   "2026-10-15",
		},
		SendEmail: fiscalisto.Bool(true),
		Metadata:  map[string]string{"corrida": "2026-19"},
	}, fiscalisto.WithIdempotencyKey("nomina-2026-10-q1-9"))
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(invoice.ID)
}
```

```java tab="Java"
import com.fiscalisto.FiscalistoClient;
import com.fiscalisto.RequestOptions;
import com.fiscalisto.model.CreatePayrollReceiptParams;
import com.fiscalisto.model.CreatePayrollReceiptParamsPeriod;
import java.util.Map;

// La llave viene de FISCALISTO_API_KEY.
var fiscalisto = new FiscalistoClient();

var invoice = fiscalisto.payrollReceipts().create(new CreatePayrollReceiptParams()
        .setEmployee("emp_OufpKqnrvx9p4gtWHOcPMsq25QUp6Licjr")
        .setPeriod(new CreatePayrollReceiptParamsPeriod()
                .setStart("2026-10-01")
                .setEnd("2026-10-15"))
        .setSendEmail(true)
        .setMetadata(Map.of("corrida", "2026-19")), RequestOptions.idempotencyKey("nomina-2026-10-q1-9"));
System.out.println(invoice.getId());
```

```csharp tab="C#"
using Fiscalisto;

// La llave viene de FISCALISTO_API_KEY.
var fiscalisto = new FiscalistoClient();

var invoice = await fiscalisto.PayrollReceipts.CreateAsync(new CreatePayrollReceiptParams
{
    Employee = "emp_OufpKqnrvx9p4gtWHOcPMsq25QUp6Licjr",
    Period = new() { Start = "2026-10-01", End = "2026-10-15" },
    SendEmail = true,
    Metadata = new() { ["corrida"] = "2026-19" },
}, new RequestOptions { IdempotencyKey = "nomina-2026-10-q1-9" });
```

La respuesta es una [factura](https://fiscalisto.com/docs/api/facturas) de `type: "N"` con su `uuid`, su PDF y su XML, y con el recibo en `payroll`. Llega también el webhook `invoice.stamped`. Con `send_email` el empleado recibe el PDF y el XML en su `email`; si no tiene, contesta `400` `parameter_missing` antes de timbrar.

Un empleado tiene un solo recibo por periodo: pedirlo otra vez (aun con otra `Idempotency-Key`) contesta el que ya tiene, sin timbrar otro. Un periodo que se cruza con otro recibo vigente del mismo empleado, o más largo que su periodicidad (un mes en una nómina semanal), contesta `payroll_invalid`, para no pagar dos veces los mismos días.

## Corregir un recibo

Un recibo timbrado no se edita. Cancélelo con [`POST /v1/invoices/{id}/cancel`](https://fiscalisto.com/docs/api/cancelacion) (no pide aceptación del empleado) y vuelva a timbrar el periodo: un periodo con su recibo cancelado se puede timbrar de nuevo.

## Listarlos

Los recibos son facturas de tipo N: [`GET /v1/invoices?type=N`](https://fiscalisto.com/docs/api/referencia/facturas/list-invoices) los da, los más recientes primero, y [`GET /v1/employees`](https://fiscalisto.com/docs/api/referencia/nomina/list-employees) a los empleados.

## Lo que no hace

- Nómina extraordinaria (aguinaldo, finiquito, PTU): solo nómina ordinaria.
- Percepciones o deducciones que usted escriba (bonos, préstamos, Infonavit): el recibo lleva el sueldo, el ISR, el subsidio y las cuotas del IMSS.
