Datos de negocio de la factura
Calendario de pagos, referencias de cabecera y de línea, periodo de facturación, literales legales y centros administrativos DIR3 en una factura — omitir frente a null, versiones y cómo cambiarlos tras emitir.
Además de su contenido fiscal, una factura puede llevar datos de negocio estructurados: el calendario de pagos acordado, las referencias que el cliente pide ver (contrato, transacción, expediente, albaranes), el periodo de facturación, literales legales comerciales y los centros administrativos DIR3 que la encaminan en el sector público. Estos datos son aditivos: una factura sin ellos se comporta exactamente como antes.
Todo vive en los mismos cuerpos que ya usas (POST /v1/companies/{company}/invoices,
PATCH /v1/companies/{company}/invoices/{invoice} y las filas de bulk-create) y vuelve en el recurso de la
factura. Todas las rutas de esta guía cuelgan de /v1/companies/{company}/…:
{company} es el id (UUID v7) del NIF con el que operas, y en los ejemplos curl
es $COMPANY_ID. Alcanzar un NIF explica cómo
resolverlo.
El ciclo de vida tiene dos fases:
- Mientras la factura es un borrador puedes crear, reemplazar y quitar cada campo.
- Al emitirla los datos se congelan con ella. Editarlos se rechaza con
422business_rule_violationy subcodeinvoice_not_editable_in_current_state. Lo único que aún puedes cambiar es el encaminamiento administrativo, añadiendo una revisión administrativa.
| Bloque | Campos de la petición | Se congela al emitir |
|---|---|---|
| Calendario de pagos | payment_terms, expected_payment_terms_version | Sí. Se valida y se congela una sola vez. |
| Referencias | business_references, lines[].business_references, lines[].delivery_notes_references, lines[].sequence_number | Sí |
| Periodo de facturación y literales | invoicing_period, legal_literals | Sí |
| Centros DIR3 | administrative_centres | El encaminamiento capturado, más las revisiones |
Omitir, null y []
La API distingue una clave ausente de una null o vacía, y la diferencia importa. La
misma regla vale para todos los campos de esta guía:
| Envías | Al crear | Al actualizar (PATCH) |
|---|---|---|
| La clave está ausente | No se guarda nada (el calendario queda desconocido). En DIR3 se heredan los centros del destinatario. | Conserva el valor actual. |
null | Igual que ausente. | Lo quita (en administrative_centres, elimina tu sustitución y vuelve a los centros heredados). Solo en un borrador. |
[] (listas) | «Ninguno» explícito. En payment_terms: un calendario vacío conocido. | Reemplaza toda la lista por una vacía. |
| Una lista | Se guarda tal cual, con su orden y sus duplicados. | Reemplaza toda la lista. |
| Un objeto | Se guarda tal cual. | Combina por clave: solo cambian las claves que envías (business_references, business_references de línea). {} no cambia nada. |
No se recorta, deduplica ni reordena nada. Los límites de texto cuentan caracteres Unicode.
Calendario de pagos
payment_terms es el calendario acordado de plazos. Es información contractual y no
registra cobros.
Con plazos, la factura vence el día de su último plazo.
- Para emitirla,
due_ondebe ser esa fecha. Undue_onausente o distinto responde422 invoice_due_date_not_last_instalment(param: due_on) antes de asignar número, y no se emite nada. Se aplica aissue, a una creación que emite en el acto medianteoptionsy a cualquier otra vía de emisión. - Un borrador conserva el
due_onque envíes, aunque sea distinto; la comprobación se hace al emitirlo. - Una actualización (
PATCH) que sustituyepayment_termsy omitedue_onllevadue_onal último plazo. Si envías los dos y no coinciden, el borrador los conserva y emitirlo responde el mismo422. - Programar o reprogramar la emisión (
schedule,reschedule) comprueba la misma regla: la factura conserva su estado y su fecha y la petición responde el mismo422. - Duplicar una factura emite el borrador con fecha de hoy: cada plazo conserva su importe y
se desplaza los días que hay entre las dos fechas de emisión, y
due_ones el último plazo desplazado. - Sin calendario,
due_ones la fecha que envíes.
| Campo | Tipo | Notas |
|---|---|---|
id | string (UUID v7) | Opcional. Si se omite, el backend asigna uno al crear. Al actualizar, envíalo para conservar la identidad de un plazo existente. null y vacío no son válidos. |
due_date | string (YYYY-MM-DD) | Una fecha real. Las fechas nunca decrecen a lo largo de la lista; se permiten fechas iguales. |
amount | string | Decimal con signo y exactamente dos decimales, distinto de cero: "40.00", "-20.00". Nunca un número JSON. |
payment_means | string | De "01" a "19", los medios de pago de Facturae 3.2.2. |
account | objeto o null | { "iban": "...", "bic": "..." }. Solo para 02 (adeudo domiciliado) y 04 (transferencia). bic es opcional. |
Los importes deben sumar exactamente total_to_pay (el total más los suplidos), con
el signo de ese importe, de modo que un total negativo lleva plazos negativos. Factuarea
nunca convierte, reparte ni redondea importes por ti. Un importe a pagar de cero solo
admite null o [].
curl -X POST https://api.factuarea.com/v1/companies/$COMPANY_ID/invoices \
-H "Authorization: Bearer fact_test_3pXnR2VbY7TcA9eFmN5z8KqW" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"client_id": "0197c5a0-4d2b-7c18-9f63-1a8e5b3d7c24",
"issued_on": "2026-10-14",
"due_on": "2026-12-13",
"lines": [
{ "description": "Mantenimiento mensual", "quantity": 1, "unit_price": 100, "tax_rate": 21 }
],
"payment_terms": [
{ "due_date": "2026-11-13", "amount": "60.50", "payment_means": "01" },
{
"due_date": "2026-12-13",
"amount": "60.50",
"payment_means": "04",
"account": { "iban": "ES9121000418450200051332", "bic": "CAIXESBBXXX" }
}
]
}'La respuesta devuelve payment_terms con las identidades, además de:
| Campo | Significado |
|---|---|
payment_terms_version | Versión del calendario. 0 cuando no hay ninguno, 1 tras la primera escritura. |
payment_terms_source | none, explicit (lo enviaste tú) o legacy (lo capturó Factuarea de una factura emitida anterior). |
payment_terms_currency, payment_terms_captured_at, payment_terms_frozen_at | La moneda (EUR) y los momentos en que se capturó y se congeló. |
Esos cinco campos son de solo lectura: enviarlos responde 422.
Cambiar el calendario de una factura existente exige expected_payment_terms_version,
un valor JSON entero (0 o más), incluso cuando envías null, [] o la misma lista.
Es el compare-and-set del calendario, independiente de cualquier otra cosa. Sin él
recibes 428 invoice_payment_terms_precondition_required; con uno obsoleto,
409 invoice_payment_terms_version_conflict con details.current_version. Para
recuperarte, vuelve a leer la factura y reaplica tu cambio sobre su
payment_terms_version.
curl -X PATCH https://api.factuarea.com/v1/companies/$COMPANY_ID/invoices/0197c5b1-7e90-7a42-b5d8-3c6f2e1a9b07 \
-H "Authorization: Bearer fact_test_3pXnR2VbY7TcA9eFmN5z8KqW" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"payment_terms": [],
"expected_payment_terms_version": 1
}'Reglas que conviene conocer:
- Editar solo descripciones, o reordenar líneas mientras el importe a pagar no cambia, no pide un calendario nuevo. Cambiar el importe a pagar mientras existe un calendario sí: debes enviar el reemplazo completo y equilibrado y su versión.
- Un plazo con
02o04puede carecer deaccountmientras la factura es un borrador. Al emitir (directa, programada o por cambio de estado) se comprueban todas las cuentas y que el calendario suma, y se congela. Un fallo revierte toda la emisión: no se consume ningún número. - Los IBAN se validan (formato y dígitos de control, de cualquier país) y se normalizan los espacios; el BIC, si se envía, conserva sus 8 u 11 caracteres.
- Duplicar una factura copia el calendario con identidades nuevas. Una rectificativa empieza sin calendario salvo que envíes uno (allí los plazos negativos son válidos).
- En un
POST /v1/companies/{company}/invoicescon unexternal_idque ya existe, la petición es una actualización y sigue las reglas de actualización.
Referencias, periodo y literales
Las referencias de cabecera van en business_references, un objeto cerrado con tres
claves, de hasta 20 caracteres cada una: receiver_contract_reference,
receiver_transaction_reference y file_reference.
Las referencias de línea van en lines[].business_references: cinco pares de
referencia (hasta 20 caracteres) y fecha (YYYY-MM-DD):
| Referencia | Fecha |
|---|---|
issuer_contract_reference | issuer_contract_date |
issuer_transaction_reference | issuer_transaction_date |
receiver_contract_reference | receiver_contract_date |
receiver_transaction_reference | receiver_transaction_date |
file_reference | file_date |
Una referencia sin fecha es válida; una fecha sin su referencia no lo es, una vez combinada la edición parcial. Los objetos de cabecera no admiten fechas.
Cada línea admite también delivery_notes_references, una lista de
{ "number": "ALB-2026-014", "date": "2026-10-02" } (number de hasta 30 caracteres,
date opcional), y sequence_number: null o un entero de 0 a 2147483647 (0 es
válido; un string, un decimal o un booleano no).
invoicing_period es un objeto con las dos fechas, start_date y end_date, fechas
reales con el inicio igual o anterior al fin. legal_literals es una lista ordenada de
textos comerciales de hasta 250 caracteres, que conserva los duplicados. Son
independientes de las legal_mentions fiscales que la factura ya calcula y nunca las
sustituyen.
{
"business_references": { "file_reference": "EXP-2026-0042" },
"invoicing_period": { "start_date": "2026-10-01", "end_date": "2026-10-31" },
"legal_literals": ["Operación sujeta al convenio marco 2026."],
"lines": [
{
"description": "Mantenimiento mensual",
"quantity": 1,
"unit_price": 100,
"tax_rate": 21,
"business_references": {
"issuer_contract_reference": "C-1",
"issuer_contract_date": "2026-01-15"
},
"delivery_notes_references": [{ "number": "ALB-2026-014", "date": "2026-10-02" }],
"sequence_number": 0
}
]
}Identidad de línea. En la respuesta cada línea tiene un id (UUID v7). En un PATCH,
envía ese id para indicar qué línea quieres decir: puedes reordenar las líneas y cada
una conserva sus referencias. Una línea sin id es nueva. Al crear, lines[].id se
rechaza, igual que un id que pertenezca a otra factura, una línea retirada o un
duplicado. Las rectificativas heredan las referencias de línea solo de la línea que
nombras con lines[].source_line_id, nunca por posición; los datos de cabecera
(business_references, invoicing_period, legal_literals y administrative_centres)
no se aceptan en una rectificativa.
Centros administrativos DIR3
Las facturas a la administración pública llevan hasta cuatro centros DIR3, cada uno con un rol. Son los que usa la facturación a FACe para encaminar:
role_code | Rol |
|---|---|
01 | Oficina contable |
02 | Órgano gestor |
03 | Unidad tramitadora |
04 | Proponente (opcional) |
administrative_centres es una lista de { "role_code", "code", "name" }. Los roles son
únicos. code se recorta y se pasa a mayúsculas, y debe cumplir ^[A-Z][A-Z0-9]{8,9}$
(por ejemplo L01280796); name es un texto opcional de hasta 40 caracteres, que se
conserva tal cual. La respuesta ordena los centros por rol.
De dónde salen los centros, por orden:
- La sustitución de la factura (lo que envías en
administrative_centres). - La instantánea que la factura capturó del perfil del cliente al crearse (y que se actualiza mientras es un borrador y cambias el cliente).
- Solo en una factura anterior cuyo encaminamiento capturado es desconocido, los códigos actuales del cliente.
La respuesta expone los tres: administrative_centres (efectivos),
administrative_snapshot y administrative_override, con administrative_version y
administrative_revision_id. Fíjate en los dos tipos de vacío:
| Valor | Significa |
|---|---|
administrative_snapshot: null | Desconocido (legacy). Se permite recurrir al cliente. |
administrative_snapshot: [] | Conocido y sin centros. Nunca se rellena con el cliente actual. |
administrative_override: null | Sin sustitución: se aplica la instantánea. |
administrative_override: [] | Sustitución explícita sin ningún centro. |
Al actualizar, null elimina tu sustitución y [] la reemplaza por una vacía. El rol
04 sobrevive aunque 01 a 03 estén vacíos. El encaminamiento capturado no se
reescribe cuando el cliente cambia después.
Los códigos del cliente (decisión DEC-06)
Los códigos salen del perfil de cliente:
PATCH /v1/companies/{company}/contacts/{contact}/customer-profile
acepta dir3_accounting_office, dir3_managing_body, dir3_processing_unit y
dir3_proponent, cada uno con el mismo formato de código. Los cuatro códigos siguen
una misma regla de omisión: la operación reemplaza el perfil de cliente, así que un
código DIR3 que dejes fuera se borra, dir3_proponent incluido. Envía siempre los
cuatro que quieras conservar. Cambiarlos nunca toca facturas ni envíos a FACe ya
creados.
curl -X PATCH https://api.factuarea.com/v1/companies/$COMPANY_ID/contacts/0197a2a8-4cf0-7a31-9a5e-3f2b8c1d6e42/customer-profile \
-H "Authorization: Bearer fact_test_3pXnR2VbY7TcA9eFmN5z8KqW" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"dir3_accounting_office": "L01280796",
"dir3_managing_body": "L01280796",
"dir3_processing_unit": "L01280796",
"dir3_proponent": "L01280797"
}'Revisa el encaminamiento tras emitir
Una factura en estado issued u overdue no puede cambiar sus datos de negocio, pero su
encaminamiento administrativo sí se puede corregir. Cada corrección es una adición:
una revisión nueva con su identidad, versión, motivo y autor. No vuelve a emitir, no
envía ni altera importes, fechas, identidades legales, el calendario de pagos ni el PDF.
curl https://api.factuarea.com/v1/companies/$COMPANY_ID/invoices/0197c5b1-7e90-7a42-b5d8-3c6f2e1a9b07/administrative-revisions \
-H "Authorization: Bearer fact_test_3pXnR2VbY7TcA9eFmN5z8KqW"{
"data": {
"invoice_id": "0197c5b1-7e90-7a42-b5d8-3c6f2e1a9b07",
"version": 1,
"snapshot": [
{ "role_code": "01", "code": "L01280796", "name": null },
{ "role_code": "02", "code": "L01280796", "name": null },
{ "role_code": "03", "code": "L01280796", "name": null }
],
"override": null,
"revisions": []
}
}Para corregir el encaminamiento, envía la lista completa y la versión que leíste:
curl -X POST https://api.factuarea.com/v1/companies/$COMPANY_ID/invoices/0197c5b1-7e90-7a42-b5d8-3c6f2e1a9b07/administrative-revisions \
-H "Authorization: Bearer fact_test_3pXnR2VbY7TcA9eFmN5z8KqW" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"administrative_centres": [
{ "role_code": "01", "code": "L01280796", "name": null },
{ "role_code": "02", "code": "L01280796", "name": null },
{ "role_code": "03", "code": "L01280798", "name": "Unidad corregida" },
{ "role_code": "04", "code": "L01280797", "name": null }
],
"reason": "La unidad tramitadora indicada por el cliente era otra.",
"expected_version": 1
}'Responde 201 con la revisión recién creada y su versión, aunque se confirme otra
revisión justo después:
{
"data": {
"id": "0197c5c2-0f31-7b74-8d29-6e4a1c7b3d58",
"version": 2,
"administrative_centres": [
{ "role_code": "01", "code": "L01280796", "name": null },
{ "role_code": "02", "code": "L01280796", "name": null },
{ "role_code": "03", "code": "L01280798", "name": "Unidad corregida" },
{ "role_code": "04", "code": "L01280797", "name": null }
],
"reason": "La unidad tramitadora indicada por el cliente era otra.",
"created_at": "2026-10-14T10:05:41.000000Z",
"actor_id": "0197a001-3c5d-7e12-8a47-5b9c2d1f6e80",
"correlation_id": null
},
"administrative_version": 2
}expected_versiones un campo del cuerpo (un entero de1o más) y la única protección: unIf-Matchde la factura no se aplica. Sin él,428invoice_administrative_precondition_required; obsoleto,409invoice_administrative_version_conflictcondetails.current_version. Vuelve a leer el historial y reintenta sobre esa versión.reasones obligatorio, de 1 a 500 caracteres.administrative_centreses obligatorio y puede ser[]para registrar «sin encaminamiento».- Solo las facturas
issuedyoverdueaceptan una revisión; un borrador, una factura programada, cancelada o anulada responde422business_rule_violationcon subcodeinvoice_not_editable_in_current_state(un borrador se edita conPATCH). - La revisión forma parte del historial de la factura; un envío a FACe que ya estaba preparado conserva el encaminamiento que congeló, y el intento siguiente usa el nuevo.
Scopes: invoices:read para listar, invoices:write para añadir. El servidor MCP ofrece
list_invoice_administrative_revisions y revise_invoice_administrative_routing.
Errores
| HTTP | code | Cuándo |
|---|---|---|
| 422 | invalid_invoice_business_data | Una referencia, el periodo, un literal, un centro, el id de una línea o un sequence_number no es válido. param es la ruta exacta, por ejemplo lines.0.business_references.issuer_contract_date. |
| 422 | invalid_invoice_payment_terms | Un plazo no es válido (payment_terms.N.amount, .id, .account…), el calendario no suma o se envió un campo de solo lectura. |
| 422 | invoice_due_date_not_last_instalment | La factura tiene calendario de pagos y se emite con un due_on ausente o distinto de la fecha del último plazo (param: due_on). Pon esa fecha, o ajusta los plazos, y vuelve a emitir. Consulta Calendario de pagos. |
| 428 | invoice_payment_terms_precondition_required | Cambias el calendario de una factura existente sin expected_payment_terms_version. |
| 409 | invoice_payment_terms_version_conflict | expected_payment_terms_version está obsoleto (details.current_version). |
| 428 | invoice_administrative_precondition_required | Una revisión administrativa sin expected_version. |
| 409 | invoice_administrative_version_conflict | expected_version está obsoleto (details.current_version). |
| 422 | business_rule_violation / invoice_not_editable_in_current_state | Editas los datos de una factura emitida, o revisas el encaminamiento de un borrador. |
| 404 | invoice_not_found | La factura no existe o pertenece a otra empresa. |
| 403 | insufficient_scope | A la clave le falta invoices:read o invoices:write. |
{
"error": {
"type": "invalid_request_error",
"code": "invalid_invoice_business_data",
"message": "Los datos comerciales de la factura no son válidos.",
"param": "lines.0.business_references.issuer_contract_date",
"request_id": "req_01JBVH7K9Y4N3CDQ2EHJB1AGSV",
"doc_url": "https://docs.factuarea.com/guides/errors#invalid_invoice_business_data"
}
}En bulk-create cada fila se valida por separado y una fila incorrecta se informa en
results[] sin hacer fallar a las demás; consulta
Operaciones masivas.
Relacionado
- Facturación a FACe: cómo viajan los centros efectivos y el calendario en el XML de FacturaE.
- Facturas rectificativas: qué hereda una rectificativa y qué no puede llevar.
- Presentación de documentos: el PDF que imprime estos datos.
- Importes y fechas: decimales en string y formatos de fecha.