Ir al contenido principal

Facturas de venta recurrentes

Crea automatizaciones de facturas recurrentes mediante la API. Configura facturas mensuales, trimestrales o anuales para tus clientes.

Facturas de venta recurrentes

Una factura recurrente es una plantilla de factura programada: cuando llega el momento configurado, FacturaDirecta genera automáticamente la factura real a partir de la plantilla. Útil para suscripciones, mantenimientos, alquileres, retainers y cualquier facturación periódica con importes y conceptos estables.

En los ejemplos de esta página:

  • Los UUIDs (aut_…, con_…, upl_…) son ilustrativos. Cada empresa tiene los suyos; sustitúyelos por los identificadores reales que devuelve la API.

  • El ID de impuesto S_IVA_21 es el del catálogo por defecto para IVA 21% en ventas. Recupera el catálogo real con GET /{companyId}/settings/taxes/sales. Ver Impuestos.

Conceptualmente: una automatización con action: createDocument

Una factura recurrente es técnicamente una automatización (content.type: "automation"). Tiene un trigger (cuándo se dispara) y una action (qué hace al dispararse, en este caso crear una factura). El prefijo del identificador es aut_<uuid> (de "automation").

La API pública expone hoy un único uso de las automatizaciones: facturas de venta recurrentes (action.type: "createDocument", action.template.type: "invoice"). El recurso puede extenderse a otras recurrencias en el futuro.

Doble scope

A diferencia del resto de recursos, cada operación de recurring requiere dos scopes simultáneamente:

  • Las operaciones de lectura requieren recurring:read y invoices:read.

  • Las operaciones de escritura requieren recurring:write y invoices:write.

El motivo: la recurrente toca dos dominios — la programación (recurring) y la factura que genera (invoices). Quien gestiona recurrentes debe poder leer/escribir ambos.

Estructura

  • content.type — siempre "automation".

  • content.uuid — identificador inmutable, prefijo aut_.

  • content.main:

    • title — nombre descriptivo de la recurrente.

    • enabled — true/false. Si false, las próximas ejecuciones programadas se omiten sin perderse en el calendario.

    • trigger — cuándo se dispara (ver Trigger y rrule).

    • action — qué hace al dispararse (ver Action: plantilla de factura).

  • content.attachments — adjuntos vinculados (ver Adjuntos).

Trigger y rrule

El trigger sigue el estándar RFC 5545 (iCalendar) en una versión simplificada. Forma:

"trigger": {
  "type": "recurring",
  "rrule": {
    "freq": "monthly",
    "interval": 1,
    "dtstart": "2026-06-01T06:00:00.000Z",
    "until": "2027-06-01T06:00:00.000Z",
    "bymonthday": 1
  },
  "daysAdvance": 0
}

Campos de rrule:

  • freq (obligatorio) — frecuencia base. Valores: daily, weekly, monthly, yearly.

  • interval (obligatorio, entero ≥1) — cada cuántas unidades de freq. Ejemplos: freq: "monthly", interval: 1 (mensual); freq: "monthly", interval: 3 (trimestral); freq: "weekly", interval: 2 (cada dos semanas).

  • dtstart (obligatorio) — fecha-hora de inicio en ISO 8601. Solo se evalúan ejecuciones a partir de esta fecha.

  • until o count (opcional, mutuamente excluyentes) — fin del calendario: por fecha o por número de ejecuciones totales.

  • byweekday (opcional, 0-6) — para freq weekly o monthly, fija el día de la semana (0=lunes, 6=domingo).

  • bymonthday (opcional) — para freq monthly o yearly, día del mes (1-31 o -1 para el último día del mes). Para freq: monthly el máximo aceptado es 28 (para evitar meses sin ese día).

  • bysetpos (opcional) — para freq: monthly, posición ordinal del día de la semana en el mes: 1-4 para "el primer/segundo/.../cuarto byweekday", -1 para "el último byweekday". Requiere byweekday. Ejemplo: byweekday: 2, bysetpos: -1 = "el último miércoles del mes".

  • bymonth (opcional, 1-12) — para freq: yearly, mes del año.

Otros campos del trigger:

  • daysAdvance — reservado para uso futuro. Indicar siempre 0.

Action: plantilla de factura

content.main.action describe qué documento se genera. Forma:

"action": {
  "type": "createDocument",
  "template": {
    "type": "invoice",
    "main": {
      "docNumber": { "series": "FP" },
      "contact": "con_2c4f8e21-7b3a-4d9c-9e1f-a8b7c6d5e4f3",
      "currency": "EUR",
      "lines": [
        {
          "quantity": 1,
          "unitPrice": 100,
          "tax": ["S_IVA_21"],
          "text": "Mantenimiento mensual"
        }
      ]
    }
  }
}

template.main es una estructura equivalente a la de una factura de venta normal (ver Facturas de venta). Puede incluir customFields, un mapa de valores indexado por el ID estable cfi_<uuid v4> de cada campo personalizado. Las definiciones borradas siguen siendo válidas; un ID desconocido o con formato incorrecto produce 400 Bad Request.

Cuando llega el momento programado, FacturaDirecta crea una factura con los datos de esta plantilla, asignando un nuevo número de documento y la fecha actual.

Operaciones

Lista de facturas recurrentes

GET /{companyId}/recurring/invoices devuelve las facturas recurrentes de la empresa, paginadas.

Parámetros de consulta específicos:

  • minNextScheduledDate, maxNextScheduledDate — rango de fecha de la próxima ejecución programada (ISO 8601). Útil para identificar qué recurrentes están a punto de ejecutarse o cuáles ya vencieron.

  • series — serie de numeración de la factura plantilla.

  • enabled — true/false para filtrar activas/inactivas.

  • freq — frecuencia (daily/weekly/monthly/yearly).

  • interval — intervalo entero.

  • contact — ID de contacto de la factura plantilla.

  • hasContact — true/false.

  • minTotal, maxTotal — rango de importe de la plantilla.

  • currency — código ISO 4217.

  • country — código país ISO 3166-1 Alpha-2.

  • allTheseTags, anyOfTheseTags, hasTags — filtros por etiquetas.

  • sortBy — campo de orden.

  • related — valores admitidos:

    • nextScheduledTime — devuelve la próxima fecha-hora prevista.

    • upcomingSceheduledTimes — devuelve hasta las próximas 5 fechas programadas. (Nombre con typo histórico en el openapi; se mantiene por compatibilidad.)

    • taxIds — devuelve en related.objects el detalle de los impuestos aplicados en la plantilla.

Parámetros globales aceptados:

Acepta además los parámetros estándar offset, limit, minCreationDate, maxCreationDate, minModificationDate, maxModificationDate y el header accept-version. Ver Paginación y Autenticación.

Copy as cURL

curl -s -H "Authorization: Bearer $ACCESS_TOKEN" \
  "https://app.facturadirecta.com/api/$COMPANY_ID/recurring/invoices?enabled=true&freq=monthly&related=nextScheduledTime"

Crear factura recurrente

POST /{companyId}/recurring/invoices crea una factura recurrente.

Parámetros del body:

  • content.type — siempre "automation".

  • content.main.title (obligatorio) — nombre descriptivo.

  • content.main.enabled (opcional, por defecto true).

  • content.main.trigger (obligatorio) — ver Trigger y rrule.

  • content.main.action (obligatorio) — ver Action: plantilla de factura.

  • tags (opcional).

Notas:

  • La primera ejecución no recupera fechas anteriores al día de creación. Si dtstart está en el pasado, el calendario conserva esa referencia, pero el servidor espera a la primera ocurrencia del mismo día o posterior. Así evita generar una factura histórica que no solicitaste.

  • Si la primera ocurrencia vence por un error técnico, sigue pendiente durante el resto de su periodo. Una recurrente mensual, por ejemplo, puede recuperar esa primera factura hasta que llegue la siguiente ocurrencia mensual.

  • Si enabled: false, la recurrente se guarda pero las ejecuciones programadas se omiten hasta que se reactive.

  • Los planes 2026 limitan el número de recurrentes activas a la vez (Gratis 2, Bronce 20, Plata 200, Oro y Diamante sin límite; cuentan todas las automatizaciones activas, no solo las facturas). Con el cupo lleno, crear una recurrente con enabled: true devuelve 403 con el código plan_limit_exceeded (ver Errores); crearla con enabled: false siempre es posible. Desactivar o borrar una recurrente libera hueco.

  • La respuesta es la recurrente creada completa, en el mismo formato que Obtener una factura recurrente.

Parámetros globales aceptados: accept-version.

Ejemplo de request JSON

Recurrente mensual el día 1 de cada mes, desde junio de 2026 durante 12 meses:

{
  "content": {
    "type": "automation",
    "main": {
      "title": "Mantenimiento mensual - Acme",
      "enabled": true,
      "trigger": {
        "type": "recurring",
        "rrule": {
          "freq": "monthly",
          "interval": 1,
          "dtstart": "2026-06-01T06:00:00.000Z",
          "count": 12,
          "bymonthday": 1
        }
      },
      "action": {
        "type": "createDocument",
        "template": {
          "type": "invoice",
          "main": {
            "docNumber": { "series": "FP" },
            "contact": "con_2c4f8e21-7b3a-4d9c-9e1f-a8b7c6d5e4f3",
            "currency": "EUR",
            "lines": [
              {
                "quantity": 1,
                "unitPrice": 100,
                "tax": ["S_IVA_21"],
                "text": "Mantenimiento mensual"
              }
            ]
          }
        }
      }
    }
  }
}

Copy as cURL

curl -s -H "Authorization: Bearer $ACCESS_TOKEN" -H "Content-Type: application/json" \
  -d '@recurringInvoice.json' \
  "https://app.facturadirecta.com/api/$COMPANY_ID/recurring/invoices"

Obtener una factura recurrente

GET /{companyId}/recurring/invoices/{id} devuelve una factura recurrente por ID.

Parámetros específicos:

Parámetros globales aceptados: accept-version.

Copy as cURL

curl -s -H "Authorization: Bearer $ACCESS_TOKEN" \
  "https://app.facturadirecta.com/api/$COMPANY_ID/recurring/invoices/aut_8a2c4e91-3b5d-4f7c-9e1a-2d4b6c8e0a1f?related=nextScheduledTime&related=upcomingSceheduledTimes"

Actualizar factura recurrente

PUT /{companyId}/recurring/invoices/{id} sustituye el contenido completo de la recurrente. No es un PATCH.

Casos típicos:

  • Cambiar la plantilla (action.template): por ejemplo, subir el importe de la suscripción mensual. Los documentos ya emitidos no se ven afectados; solo las próximas ejecuciones generan facturas con el nuevo importe.

  • Cambiar la frecuencia (trigger.rrule): el calendario conserva dtstart como referencia y descarta las ocurrencias anteriores al día de la actualización si todavía no hubo una ejecución correcta.

  • Activar o desactivar (enabled): conserva la configuración. Al reactivar una recurrente sin ejecuciones correctas, no se recuperan ocurrencias anteriores al día de la actualización. Reactivar con el cupo de recurrentes activas del plan lleno devuelve 403 plan_limit_exceeded; editar una recurrente que ya está activa no consume hueco.

Parámetros globales aceptados: accept-version.

Copy as cURL

curl -s -H "Authorization: Bearer $ACCESS_TOKEN" -H "Content-Type: application/json" -X PUT \
  -d '@recurringInvoice.json' \
  "https://app.facturadirecta.com/api/$COMPANY_ID/recurring/invoices/aut_8a2c4e91-3b5d-4f7c-9e1a-2d4b6c8e0a1f"

Borrar factura recurrente

DELETE /{companyId}/recurring/invoices/{id} elimina la recurrente. Las facturas ya emitidas por la recurrente se conservan. Solo se cancela el calendario de ejecuciones futuras.

Si quieres pausar temporalmente sin perder configuración, usa enabled: false en lugar de borrar.

Parámetros globales aceptados: accept-version.

Copy as cURL

curl -s -H "Authorization: Bearer $ACCESS_TOKEN" -X DELETE \
  "https://app.facturadirecta.com/api/$COMPANY_ID/recurring/invoices/aut_8a2c4e91-3b5d-4f7c-9e1a-2d4b6c8e0a1f"

Actualizar etiquetas

PUT /{companyId}/recurring/invoices/{id}/tags reemplaza el conjunto de etiquetas sin tocar el resto del contenido.

Ejemplo de request JSON

{
  "tags": ["suscripcion", "premium"]
}

Copy as cURL

curl -s -H "Authorization: Bearer $ACCESS_TOKEN" -H "Content-Type: application/json" -X PUT \
  -d '{"tags":["suscripcion","premium"]}' \
  "https://app.facturadirecta.com/api/$COMPANY_ID/recurring/invoices/aut_8a2c4e91-3b5d-4f7c-9e1a-2d4b6c8e0a1f/tags"

Generar muestra en PDF

PUT /{companyId}/recurring/invoices/{id}/pdf genera una URL temporal con una muestra de la factura que se emitiría, en PDF. Es solo una previsualización: no crea ninguna factura real ni avanza el calendario.

Parámetros del body:

  • mode (opcional) — "attachment" (URL para descargar como adjunto, por defecto), "inline" (visualización en línea) o "print" (URL HTML que carga el PDF y lo envía a imprimir).

Parámetros globales aceptados: accept-version.

Copy as cURL

curl -s -H "Authorization: Bearer $ACCESS_TOKEN" -H "Content-Type: application/json" -X PUT \
  -d '{"mode":"inline"}' \
  "https://app.facturadirecta.com/api/$COMPANY_ID/recurring/invoices/aut_8a2c4e91-3b5d-4f7c-9e1a-2d4b6c8e0a1f/pdf"

Adjuntos

Una factura recurrente puede tener adjuntos vinculados (p. ej. un contrato base). Estos adjuntos viajan en cada factura generada por la recurrente.

Listar adjuntos

GET /{companyId}/recurring/invoices/{id}/attachments devuelve los adjuntos vinculados.

curl -s -H "Authorization: Bearer $ACCESS_TOKEN" \
  "https://app.facturadirecta.com/api/$COMPANY_ID/recurring/invoices/aut_8a2c4e91-3b5d-4f7c-9e1a-2d4b6c8e0a1f/attachments"

Vincular adjuntos

POST /{companyId}/recurring/invoices/{id}/attachments añade adjuntos a partir de uploads previos.

Parámetros del body:

  • uploadIds — array de identificadores upl_<uuid>. Mínimo uno.

curl -s -H "Authorization: Bearer $ACCESS_TOKEN" -H "Content-Type: application/json" \
  -d '{"uploadIds":["upl_6f8e9b42-1d3c-4a7f-b2e4-9c1d5e7f3a6b"]}' \
  "https://app.facturadirecta.com/api/$COMPANY_ID/recurring/invoices/aut_8a2c4e91-3b5d-4f7c-9e1a-2d4b6c8e0a1f/attachments"

Eliminar un adjunto

DELETE /{companyId}/recurring/invoices/{id}/attachments/{attachmentIndex} elimina un adjunto. attachmentIndex es la posición en el array (basada en cero).

curl -s -H "Authorization: Bearer $ACCESS_TOKEN" -X DELETE \
  "https://app.facturadirecta.com/api/$COMPANY_ID/recurring/invoices/aut_8a2c4e91-3b5d-4f7c-9e1a-2d4b6c8e0a1f/attachments/0"

Recomendaciones

  • Empieza con enabled: false mientras pruebas: la recurrente queda configurada sin generar facturas.

  • Usa related=nextScheduledTime al consultar para saber cuándo se ejecutará por próxima vez. Y upcomingSceheduledTimes para ver las siguientes 5 fechas (útil para validar que el rrule resuelve al calendario que esperas).

  • Para suscripciones que cambian de precio, actualiza la plantilla (action.template.main.lines[].unitPrice) en cualquier momento. Las ejecuciones futuras usan el nuevo precio sin tocar las pasadas.

  • dtstart en el futuro es válido y útil para programar recurrentes que arranquen más adelante.

  • Para pausar temporalmente, prefiere enabled: false sobre borrado. Conserva todo el calendario y la configuración.

Errores comunes

  • 400 ValidationError — rrule con combinación inválida (until y count a la vez, bymonthday > 28 con freq: monthly, bysetpos sin byweekday...).

  • 400 ValidationError — daysAdvance != 0 (reservado, debe quedar en cero).

  • 400 ValidationError — action.template.type distinto de invoice. Hoy es el único valor soportado.

  • 409 Conflict — series o docNumber de la plantilla en conflicto con otra factura emitida.

Ver Errores y validaciones para el formato general.

Referencia exhaustiva

Esta página cubre los matices funcionales y los casos típicos. Para la referencia exhaustiva de todos los campos del body y la respuesta, consulta el Swagger UI o el openapi crudo.

Endpoints

Método

Path

operationId

Scopes

Descripción

GET

/{companyId}/recurring/invoices

getRecurringInvoices

invoices:read, recurring:read

Lista de facturas de venta recurrentes

GET

/{companyId}/recurring/invoices/{id}

getRecurringInvoice

invoices:read, recurring:read

Obtener una factura de venta recurrente

GET

/{companyId}/recurring/invoices/{id}/attachments

getRecurringInvoiceAttachments

invoices:read, recurring:read

Listar adjuntos de una factura recurrente

POST

/{companyId}/recurring/invoices

createRecurringInvoice

invoices:write, recurring:write

Crea factura de venta recurrente

POST

/{companyId}/recurring/invoices/{id}/attachments

addRecurringInvoiceAttachments

invoices:write, recurring:write

Vincular adjuntos a una factura recurrente

PUT

/{companyId}/recurring/invoices/{id}

updateRecurringInvoice

invoices:write, recurring:write

Actualizar factura recurrente

PUT

/{companyId}/recurring/invoices/{id}/pdf

createRecurringInvoicePDF

invoices:read, recurring:read

Generar muestra de la factura de venta recurrente en formato PDF

PUT

/{companyId}/recurring/invoices/{id}/tags

updateRecurringInvoiceTags

invoices:write, recurring:write

Actualizar etiquetas de factura de venta recurrente

DELETE

/{companyId}/recurring/invoices/{id}

deleteRecurringInvoice

invoices:write, recurring:write

Borrar factura de venta recurrente

DELETE

/{companyId}/recurring/invoices/{id}/attachments/{attachmentIndex}

deleteRecurringInvoiceAttachment

invoices:write, recurring:write

Eliminar adjunto de una factura recurrente

Scopes

  • invoices:read — Lectura de facturas.

  • invoices:write — Modificación de facturas.

  • recurring:read — Lectura de documentos recurrentes.

  • recurring:write — Modificación de documentos recurrentes.

¿Ha quedado contestada tu pregunta?