Faxtal

Facturas recurrentes

Una plantilla recurrente genera facturas de forma periódica según un calendario. Desde la API puedes calcular el calendario sin guardar, crear y editar plantillas, gestionar cada fecha y actualizar precios en bloque.

Todas las llamadas usan la URL base https://app.faxtal.com/api/v1.1 y la cabecera X-API-Key (ver Autenticación).

OperaciónScope de la API key
Consultar, vista previa de calendario y de preciosrecurring:read
Crear, editar, pausar, reanudar, finalizar y gestionar fechasrecurring:write
Plantilla que emite (issue o issue_and_send)además, invoices:issue
Actualizar el catálogo desde una actualización de preciosademás, parties:write
Propuesta desde una factura emitidaademás, invoices:read

Sin el scope necesario, la API responde 403 con el código scope_missing. Si el plan de la empresa no incluye la función, responde 402 con feature_outside_plan.


Plantillas

Método y rutaScopeQué hace
POST /recurring-templates/previewrecurring:readCalcula el calendario sin guardar nada
GET /recurring-templatesrecurring:readLista las plantillas. Filtro opcional status=active|paused|finished
POST /recurring-templatesrecurring:writeCrea una plantilla. Responde 201
GET /recurring-templates/{template_id}recurring:readConsulta una plantilla
PUT /recurring-templates/{template_id}recurring:writeEdita una plantilla
POST /recurring-templates/{template_id}/pauserecurring:writePausa la plantilla
POST /recurring-templates/{template_id}/resumerecurring:writeLa reanuda
POST /recurring-templates/{template_id}/finishrecurring:writeLa finaliza. No se puede deshacer
GET /recurring-templates/from-invoice/{invoice_id}recurring:read e invoices:readPropuesta de plantilla desde una factura emitida. No guarda

Cuerpo de una plantilla

CampoDescripción
nameNombre de la plantilla.
canonical_templateCanónico v1.1 parcial: {"invoice": {"customer", "header", "issue_data", "lines", "payment_details"}}.
scheduleCalendario (ver la tabla siguiente).
issue_modedraft, issue o issue_and_send.
payment_methodtransfer, sepa_debit u other.
sepa_mandate_idpublic_id de un mandato activo del cliente. Obligatorio con payment_method: "sepa_debit", que además exige third_party_id y la funcionalidad de tesorería SEPA del plan. La salida de la plantilla lo devuelve.
series_codeSerie de emisión.
third_party_idCliente de la plantilla.
email_template_codePlantilla de email para issue_and_send.

Calendario (schedule):

CampoDescripción
frequencyFrecuencia: semanal, mensual, bimestral, trimestral, semestral o anual.
intervalCada cuántos periodos.
anchor_dayDía del mes.
start_dateFecha de inicio.
end_modeCómo termina: sin fin, en una fecha o tras un número de facturas.
end_dateFecha de fin, si end_mode es en una fecha.
max_occurrencesNúmero de facturas, si end_mode es por número.
period_modePeriodo facturado: el actual o el vencido.
due_daysDías hasta el vencimiento.

En los textos del canónico puedes usar las variables {mes}, {mes+1}, {mes-1}, {trimestre}, {año}, {inicio_periodo}, {fin_periodo} y {n}, que se resuelven con la fecha de cada factura.

Si al generar una factura el mandato ya no está activo, esa ocurrencia falla con sepa_mandate_inactive y la plantilla se pausa con paused_reason igual a mandate_inactive. Para reanudarla, edítala con otro sepa_mandate_id.

Calendario sin guardar

POST /api/v1.1/recurring-templates/preview recibe {canonical_template, schedule} y devuelve las fechas, los periodos y los importes. No crea nada.

curl -X POST "https://app.faxtal.com/api/v1.1/recurring-templates/preview" \
  -H "X-API-Key: fctXXXXXXXX_YYYYYYYYYYYYYYYY" \
  -H "Content-Type: application/json" \
  -d '{
    "canonical_template": { "invoice": { "lines": [] } },
    "schedule": {
      "frequency": "monthly",
      "interval": 1,
      "anchor_day": 1,
      "start_date": "2026-11-01",
      "end_mode": "never",
      "period_mode": "current",
      "due_days": 30
    }
  }'

Bloqueo optimista

PUT y las acciones pause, resume y finish llevan el campo version de la plantilla, tal como la devolvió la última lectura. Si otra persona la cambió entre medias, la API responde 409 con recurring_template_version_conflict: vuelve a leerla y repite.

curl -X POST "https://app.faxtal.com/api/v1.1/recurring-templates/42/pause" \
  -H "X-API-Key: fctXXXXXXXX_YYYYYYYYYYYYYYYY" \
  -H "Content-Type: application/json" \
  -d '{"version": 3}'

Ocurrencias

Cada fecha del calendario es una ocurrencia, identificada por su seq.

Método y rutaScopeQué hace
GET /recurring-templates/{template_id}/occurrencesrecurring:readLista las ocurrencias con su estado
POST /recurring-templates/{template_id}/occurrences/{seq}/generaterecurring:writeGenera la factura ahora. La plantilla tiene que estar activa
POST /recurring-templates/{template_id}/occurrences/{seq}/skiprecurring:writeSalta la fecha
POST /recurring-templates/{template_id}/occurrences/{seq}/restorerecurring:writeLa recupera
PATCH /recurring-templates/{template_id}/occurrences/{seq}recurring:writeCambia la fecha con {"planned_date": "2026-12-05"}. No puede ser pasada

Idempotencia

Cada factura generada lleva meta.external_ref = rec:<plantilla>:<seq>. Si reintentas una generación, no se duplica la factura.


Actualizar precios

Método y rutaScopeQué hace
POST /recurring-templates/price-updates/previewrecurring:readCalcula el cambio sin aplicarlo
POST /recurring-templates/price-updatesrecurring:writeAplica el cambio. Responde 201
GET /recurring-templates/price-updatesrecurring:readLista las actualizaciones. Filtro opcional template_id
GET /recurring-templates/price-updates/{id}recurring:readConsulta una actualización

Cuerpo de la vista previa:

{
  "scope": {
    "template_ids": [],
    "third_party_ids": [],
    "article_codes": ["CONSULT-SENIOR"],
    "series_codes": []
  },
  "criterion": "percent",
  "value": 3.5,
  "rounding_step": 0.05,
  "update_products": false
}
CampoDescripción
scopePlantillas, clientes, productos y series a los que afecta. Sin filtros, todas las plantillas activas y pausadas. Con article_codes solo cambian esas líneas.
criterionpercent, amount (importe por unidad, positivo o negativo) o new_price.
valueEl porcentaje, el importe o el precio nuevo.
rounding_stepnull (al céntimo), 0.05, 0.10, 0.50 o 1.
update_productsSi es true, aplica el mismo cambio al producto del catálogo con ese código, si su precio va en el mismo modo (con o sin IVA). Exige parties:write.

La vista previa devuelve el precio antes y después por línea, el importe de la próxima factura y del calendario, y la version de cada plantilla en templates[]. Para aplicar, envía el mismo cuerpo más template_versions: un objeto {template_id: version} con esas versiones. Si alguna plantilla cambió en medio, la API responde 409 con recurring_price_update_stale: repite la vista previa.

Aplicar cambia las plantillas y sus fechas pendientes. Las facturas ya generadas no cambian, y la actualización no se puede deshacer: se corrige con otra.


Errores

Sin el plan o el scope necesario, la API responde 402 o 403 (ver arriba). El resto de errores traen el code de esta tabla. Los conflictos de versión (recurring_template_version_conflict y recurring_price_update_stale) responden 409.

codeCausa
feature_outside_planEl plan de la empresa no incluye las facturas recurrentes.
scope_missingFalta algún scope de los de la primera tabla.
recurring_template_not_foundLa plantilla no existe o es de otra empresa.
recurring_template_version_conflictLa version enviada no es la actual.
recurring_price_update_staleAlguna plantilla cambió entre la vista previa y la aplicación.
recurring_template_not_activeLa operación exige una plantilla activa.
recurring_template_finishedLa plantilla está finalizada.
recurring_unknown_variablesLos textos usan variables que no existen.
recurring_send_requires_customerissue_and_send necesita un cliente.
recurring_occurrence_not_editableEsa fecha ya no se puede cambiar.
recurring_occurrence_date_in_pastLa fecha nueva es anterior a hoy.
recurring_price_negativeEl cambio deja un precio en negativo.
recurring_price_update_emptyEl cambio no afecta a ninguna plantilla.
products_feature_requiredupdate_products exige el catálogo de productos en el plan.
recurring_sepa_feature_requiredsepa_debit exige la funcionalidad de tesorería SEPA del plan.
recurring_sepa_requires_customersepa_debit necesita un cliente (third_party_id).
recurring_sepa_mandate_requiredFalta sepa_mandate_id.
recurring_sepa_mandate_other_customerEl mandato es de otro cliente.
sepa_mandate_inactiveEl mandato no está activo.

Servidor MCP

Cinco tools del Servidor MCP trabajan con las plantillas recurrentes.


Ver también

On this page