# Facturas recurrentes

> Rentas, suscripciones e igualas: una factura que el emisor timbra solo cada mes, semana o día, a la hora que elija, sin que usted programe nada.

Una **factura recurrente** se timbra sola en cada fecha, con los timbres de su cuenta, y se le manda al cliente si así lo pide. Usted no necesita un cron ni guardar en qué mes va: Fiscalisto timbra cada periodo una sola vez, aunque su servidor reintente o esté caído.

## Crear una

```bash tab="cURL"
curl https://api.fiscalisto.com/v1/recurring_invoices \
  -H "Authorization: Bearer $FISCALISTO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Renta oficina 3",
    "schedule": { "frequency": "monthly", "day_of_month": 1, "hour": 7 },
    "invoice": {
      "customer": {
        "tax_id": "ICV060329BY0",
        "legal_name": "INMOBILIARIA CVA",
        "tax_system": "601",
        "zip": "33826",
        "email": "pagos@cva.example"
      },
      "payment_form": "03",
      "items": [
        {
          "description": "Renta de oficina de {mes} {año}",
          "product_key": "80131500",
          "unit_price": 15000
        }
      ]
    }
  }'
```

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

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

const recurringInvoice = await fiscalisto.recurringInvoices.create({
  name: "Renta oficina 3",
  schedule: {
    frequency: "monthly",
    day_of_month: 1,
    hour: 7,
  },
  invoice: {
    customer: {
      tax_id: "ICV060329BY0",
      legal_name: "INMOBILIARIA CVA",
      tax_system: "601",
      zip: "33826",
      email: "pagos@cva.example",
    },
    payment_form: "03",
    items: [
      {
        description: "Renta de oficina de {mes} {año}",
        product_key: "80131500",
        unit_price: 15000,
      },
    ],
  },
});
```

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

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

recurring_invoice = fiscalisto.recurring_invoices.create({
    "name": "Renta oficina 3",
    "schedule": {
        "frequency": "monthly",
        "day_of_month": 1,
        "hour": 7,
    },
    "invoice": {
        "customer": {
            "tax_id": "ICV060329BY0",
            "legal_name": "INMOBILIARIA CVA",
            "tax_system": "601",
            "zip": "33826",
            "email": "pagos@cva.example",
        },
        "payment_form": "03",
        "items": [
            {
                "description": "Renta de oficina de {mes} {año}",
                "product_key": "80131500",
                "unit_price": 15000,
            },
        ],
    },
})
```

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

use Fiscalisto\Fiscalisto;

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

$recurringInvoice = $fiscalisto->recurringInvoices->create([
    'name' => 'Renta oficina 3',
    'schedule' => [
        'frequency' => 'monthly',
        'day_of_month' => 1,
        'hour' => 7,
    ],
    'invoice' => [
        'customer' => [
            'tax_id' => 'ICV060329BY0',
            'legal_name' => 'INMOBILIARIA CVA',
            'tax_system' => '601',
            'zip' => '33826',
            'email' => 'pagos@cva.example',
        ],
        'payment_form' => '03',
        'items' => [
            [
                'description' => 'Renta de oficina de {mes} {año}',
                'product_key' => '80131500',
                'unit_price' => 15000,
            ],
        ],
    ],
]);
```

```go tab="Go"
package main

import (
	"context"
	"encoding/json"
	"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()

	recurringInvoice, err := client.RecurringInvoices.Create(ctx, &fiscalisto.CreateRecurringInvoiceParams{
		Name: "Renta oficina 3",
		Schedule: fiscalisto.CreateRecurringInvoiceParamsSchedule{
			Frequency:  "monthly",
			DayOfMonth: json.RawMessage(`1`),
			Hour:       fiscalisto.Int64(7),
		},
		Invoice: fiscalisto.CreateRecurringInvoiceParamsInvoice{
			Customer: fiscalisto.ObjectOf(fiscalisto.InvoiceCreateCustomer{
				TaxID:     "ICV060329BY0",
				LegalName: "INMOBILIARIA CVA",
				TaxSystem: "601",
				Zip:       "33826",
				Email:     fiscalisto.String("pagos@cva.example"),
			}),
			PaymentForm: fiscalisto.String("03"),
			Items: []fiscalisto.InvoiceCreateItem{
				{
					Description: fiscalisto.String("Renta de oficina de {mes} {año}"),
					ProductKey:  fiscalisto.String("80131500"),
					UnitPrice:   fiscalisto.Float64(15000),
				},
			},
		},
	})
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(recurringInvoice.ID)
}
```

```java tab="Java"
import com.fiscalisto.FiscalistoClient;
import com.fiscalisto.model.CreateRecurringInvoiceParams;
import com.fiscalisto.model.CreateRecurringInvoiceParamsInvoice;
import com.fiscalisto.model.CreateRecurringInvoiceParamsSchedule;
import com.fiscalisto.model.InvoiceCreateCustomer;
import com.fiscalisto.model.InvoiceCreateItem;
import java.util.List;

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

var recurringInvoice = fiscalisto.recurringInvoices().create(new CreateRecurringInvoiceParams()
        .setName("Renta oficina 3")
        .setSchedule(new CreateRecurringInvoiceParamsSchedule()
                .setFrequency("monthly")
                .setDayOfMonth(1)
                .setHour(7))
        .setInvoice(new CreateRecurringInvoiceParamsInvoice()
                .setCustomer(new InvoiceCreateCustomer()
                        .setTaxId("ICV060329BY0")
                        .setLegalName("INMOBILIARIA CVA")
                        .setTaxSystem("601")
                        .setZip("33826")
                        .setEmail("pagos@cva.example"))
                .setPaymentForm("03")
                .setItems(List.of(
                        new InvoiceCreateItem()
                                .setDescription("Renta de oficina de {mes} {año}")
                                .setProductKey("80131500")
                                .setUnitPrice(15000)
                ))));
System.out.println(recurringInvoice.getId());
```

```csharp tab="C#"
using System.Text.Json;
using Fiscalisto;

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

var recurringInvoice = await fiscalisto.RecurringInvoices.CreateAsync(new CreateRecurringInvoiceParams
{
    Name = "Renta oficina 3",
    Schedule = new()
    {
        Frequency = "monthly",
        DayOfMonth = JsonDocument.Parse("1").RootElement,
        Hour = 7,
    },
    Invoice = new()
    {
        Customer = new InvoiceCreateCustomer
        {
            TaxId = "ICV060329BY0",
            LegalName = "INMOBILIARIA CVA",
            TaxSystem = "601",
            Zip = "33826",
            Email = "pagos@cva.example",
        },
        PaymentForm = "03",
        Items = new()
        {
            new()
            {
                Description = "Renta de oficina de {mes} {año}",
                ProductKey = "80131500",
                UnitPrice = 15000,
            },
        },
    },
});
```

`invoice` es el mismo cuerpo de [POST /v1/invoices](https://fiscalisto.com/docs/api/facturas), sin `issuer`, `folio`, `date`, `global` ni `metadata`: cada factura toma el folio siguiente y la fecha del día en que se timbra. Se revisa al crearla con las mismas reglas, así que un RFC mal escrito o una clave que no existe se rechazan ahora y no el día que toca timbrar. También puede usar un cliente de su catálogo (`"customer": "cus_…"`) o productos (`"product": "prd_…"`): cada factura toma los datos que el cliente tenga en ese momento.

Contesta `201` con la factura recurrente (`rin_…`), su siguiente fecha en `next_invoice_on` y el total de cada factura con los precios de hoy.

### Cada cuánto

| `schedule` | Qué hace |
| --- | --- |
| `"frequency": "monthly", "day_of_month": 1` | El día 1 de cada mes |
| `"frequency": "monthly", "day_of_month": "last"` | El último día de cada mes |
| `"frequency": "monthly", "interval": 12` | Una vez al año |
| `"frequency": "weekly", "interval": 2` | Cada dos semanas desde `start_date` |
| `"frequency": "daily"` | Todos los días |

`day_of_month` va del 1 al 28, o `"last"`. `start_date` (AAAA-MM-DD) es la primera factura; si no la manda, es el próximo `day_of_month` (mensual) o hoy (semanal y diaria). `hour` (0 a 23, por omisión 7) es la hora en que se timbra, en `time_zone` (por omisión `America/Mexico_City`; también `America/Cancun`, `America/Mazatlan`, `America/Hermosillo`, `America/Tijuana` y `America/Ciudad_Juarez`).

### Textos que cambian cada mes

En `description` escriba `{mes}`, `{mes anterior}`, `{mes siguiente}`, `{año}`, `{año anterior}`, `{año siguiente}` o `{periodo}` y cada factura los llena con su fecha: `Renta de oficina de {mes} {año}` sale como `Renta de oficina de noviembre 2026`. `{periodo}` sigue la frecuencia: el mes completo en una mensual (`1 al 30 de noviembre`), la semana en una semanal (`2 al 8 de noviembre`) y todos sus meses en una de varios meses (`1 de noviembre al 31 de diciembre`). La factura recurrente los guarda tal cual en `items`.

## Lo que timbra

Cada factura es una factura normal: llega `invoice.stamped` a sus [webhooks](https://fiscalisto.com/docs/api/webhooks), aparece en `GET /v1/invoices` y trae `recurring_invoice` con el id de la recurrente que la timbró. `last_invoice` y `last_invoiced_on` dicen cuál fue la última.

Si un periodo no se puede timbrar (se acabaron los timbres, el cliente se borró del catálogo, el SAT la rechazó), la recurrente guarda el motivo en `last_error`, llega `recurring_invoice.failed` una vez, y lo intenta de nuevo cada día a su hora hasta que salga. Con `catch_up: "all"` (por omisión) timbra después cada periodo que quedó pendiente, cada uno con su mes; con `"latest"`, solo el más reciente.

## Cambiarla, pausarla o timbrar ya

```bash tab="cURL"
# Pausar (active: true la reanuda desde hoy, sin timbrar lo que pasó en pausa)
curl https://api.fiscalisto.com/v1/recurring_invoices/rin_OufpKqnrvx9p7Hq2mZr1XyT5uBcW8sKdLx \
  -H "Authorization: Bearer $FISCALISTO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "active": false }'
```

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

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

const recurringInvoice = await fiscalisto.recurringInvoices.update("rin_OufpKqnrvx9p7Hq2mZr1XyT5uBcW8sKdLx", { active: false });
```

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

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

recurring_invoice = fiscalisto.recurring_invoices.update("rin_OufpKqnrvx9p7Hq2mZr1XyT5uBcW8sKdLx", {"active": False})
```

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

use Fiscalisto\Fiscalisto;

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

$recurringInvoice = $fiscalisto->recurringInvoices->update('rin_OufpKqnrvx9p7Hq2mZr1XyT5uBcW8sKdLx', ['active' => false]);
```

```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()

	recurringInvoice, err := client.RecurringInvoices.Update(ctx, "rin_OufpKqnrvx9p7Hq2mZr1XyT5uBcW8sKdLx", &fiscalisto.UpdateRecurringInvoiceParams{
		Active: fiscalisto.Bool(false),
	})
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(recurringInvoice.ID)
}
```

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

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

var recurringInvoice = fiscalisto.recurringInvoices().update("rin_OufpKqnrvx9p7Hq2mZr1XyT5uBcW8sKdLx", new UpdateRecurringInvoiceParams().setActive(false));
System.out.println(recurringInvoice.getId());
```

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

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

var recurringInvoice = await fiscalisto.RecurringInvoices.UpdateAsync("rin_OufpKqnrvx9p7Hq2mZr1XyT5uBcW8sKdLx", new UpdateRecurringInvoiceParams { Active = false });
```

- `POST /v1/recurring_invoices/{id}` cambia solo lo que mande: `name`, `schedule`, `send_email`, `catch_up`, `active` o `invoice` (la factura completa desde la siguiente vez). `schedule.start_date` mueve la siguiente fecha.
- `POST /v1/recurring_invoices/{id}/skip` salta la siguiente fecha sin timbrar.
- `POST /v1/recurring_invoices/{id}/run` timbra ya el periodo que toca, sin esperar su hora; contesta la factura. Si aún no toca, `409 recurring_not_due`. Si su hora llega mientras tanto no se timbra dos veces: es el mismo periodo.
- `DELETE /v1/recurring_invoices/{id}` la borra; las facturas que timbró se quedan.

## Límites

Un emisor tiene hasta 5,000 facturas recurrentes activas en producción y 25 en pruebas (las pausadas no cuentan). En pruebas se timbran con el PAC de pruebas, como las demás.
