Facturas
Emite facturas ordinarias y simplificadas desde tu aplicación, sigue su emisión y su correo, y consúltalas, descárgalas o anúlalas, con el plan y los permisos.
Actualizado el . 35 min de lectura
Incluido en todos los planes. Ver precios
Con /external/v1/invoices tu aplicación emite facturas en nombre de
sus usuarios, con la numeración de tu organización o en una serie que
tu organización le haya reservado, y las consulta, descarga o anula.
Todas las peticiones llevan la cabecera
X-Api-Key con una clave activa, exigen que la facturación de la
aplicación esté encendida y tienen un límite de 60 peticiones por
minuto.
Cada clave solo opera sobre las facturas de su propia aplicación, y el
userId filtra además por el usuario indicado.
Plan y permisos
Antes que el permiso de la aplicación se comprueba el plan de tu
organización. Sin el aplicativo Finanzas contratado, todos estos
endpoints responden 403 con errorCode: 'MODULE_NOT_ENABLED' y la
clave del aplicativo que falta.
| Endpoint | Aplicativo del plan | Permiso de la API (scope) |
|---|---|---|
POST /external/v1/invoices | Finanzas | crm:invoices:write y crm:invoices:issue |
POST /external/v1/invoices/validate y /validate/pdf | Finanzas | Cualquier permiso crm:invoices:* |
GET /external/v1/invoices | Finanzas | crm:invoices:read |
GET /external/v1/invoices/:id | Finanzas | crm:invoices:read |
GET /external/v1/invoices/:id/pdf | Finanzas | crm:invoices:read |
GET /external/v1/invoices/stats | Finanzas | crm:invoices:read |
GET /external/v1/invoices/series | Finanzas | crm:invoices:read |
GET /external/v1/invoices/eu-vat-rates (Próximamente) | Finanzas | crm:invoices:read |
POST /external/v1/invoices/:id/cancel | Finanzas | crm:invoices:cancel |
POST /external/v1/invoices/:id/rectifications y /rectifications/validate | Finanzas | crm:invoices:rectify |
GET /external/v1/invoices/:id/rectifications | Finanzas | crm:invoices:read |
Sin el permiso adecuado, los endpoints responden 403 INSUFFICIENT_SCOPE
con un mensaje genérico que no dice cuál falta. No hay periodo de
gracia: el permiso se exige desde la primera llamada, también en
aplicaciones creadas hace tiempo, así que concédelos antes de integrar.
crm:invoices:cancel y crm:invoices:rectify son críticos financieros:
solo los concede un Super Administrador, con un motivo. El catálogo
completo y las reglas de concesión están en
Permisos de la API.
Las acciones sobre una factura ya emitida (enviarla por correo,
cobrarla, marcarla pagada, devolver el dinero o pedir su enlace
público) están en Acciones sobre una factura emitida.
Las rectificativas, cuando devuelves el dinero con tu propia pasarela o
un contracargo deja la venta sin efecto, están en
Facturas rectificativas.
Las facturas con el IVA del país del consumidor por la ventanilla única
(taxSystem: "EU_OSS") están en «Próximamente»: hasta que estén disponibles
para tu organización, responden 403 FEATURE_COMING_SOON.
Ordinaria o simplificada
Por esta ruta se emiten dos tipos de factura, que se eligen con type:
Ordinaria (STANDARD) | Simplificada (SIMPLIFIED) | |
|---|---|---|
| Cuándo | Por defecto, si omites type. Para empresas y profesionales, o cuando el cliente la pide. | Ventas a consumidores, como una suscripción o una compra en tu aplicación (art. 7 del RD 1619/2012). |
| Numeración | La serie correlativa de tu organización (202600042) o una serie de ordinarias de tu aplicación (APP-202600001). | Su propia serie, separada de la anterior como exige la norma (T-202600001), o una serie de simplificadas de tu aplicación. |
| Importe | Sin tope legal. | Hasta 400 € impuestos incluidos. Por encima, 422 SIMPLIFIED_INVOICE_AMOUNT_EXCEEDED: emite una ordinaria. |
| Destinatario | Obligatorio y completo. | Opcional (ver la tabla siguiente). |
| Mención impresa | La que toque por sus líneas. | Además, «Factura simplificada (RD 1619/2012 art. 7)». |
El destinatario de una simplificada depende de lo que mandes en recipient:
| Lo que mandas | Lo que se imprime | Qué exige |
|---|---|---|
Sin recipient | «Consumidor final». El correo, si se envía, sale a user.email. | Nada más. |
recipient.name sin NIF | El nombre, tal cual. Sigue siendo simplificada. | Nada más. |
recipient.taxId | Una simplificada cualificada, con el destinatario identificado (art. 7.2 y 7.3). | Nombre, dirección, ciudad, código postal y país. Si falta alguno, 400 SIMPLIFIED_RECIPIENT_INCOMPLETE con la lista en missingFields. |
UTILIA OS no copia en la factura datos del usuario que no vengan en
recipient. Una ordinaria sin recipient responde
400 INVOICE_RECIPIENT_REQUIRED, y con datos incompletos,
400 INVOICE_RECIPIENT_INCOMPLETE con missingFields. Las
rectificativas no se crean aquí: tienen su propia ruta.
Crear una factura
/api/external/v1/invoicesEmite una factura ordinaria o simplificada en nombre de la aplicación con la numeración de tu organización. Como crea y emite en el mismo paso, exige a la vez crm:invoices:write y crm:invoices:issue.
Antes de tu primera factura real
Cada llamada que responde 201 emite una factura numerada que no se puede borrar. Para probar el cuerpo sin emitir nada, usa POST /external/v1/invoices/validate y su PDF de muestra: ver Probar la facturación sin emitir facturas.
Cuerpo de la petición
- userobjetoobligatorio
- Datos del usuario externo propietario de la factura.
- user.externalIdstringobligatorio
- Identificador estable del usuario en tu sistema (máximo 255 caracteres). Con él se crea o se actualiza el usuario.
- user.emailstringobligatorio
- Correo del usuario. Se valida su formato.
- user.namestring
- Nombre o razón social.
- user.taxIdstring
- NIF o CIF del usuario. Imprescindible si el receptor es el propio usuario y la factura es entre empresas. También puedes mandarlo antes con POST /external/v1/users/identify.
- user.billingAddressobjeto
- Dirección de facturación: street, city, postalCode y country obligatorios, province opcional. Si la pasas, sustituye a la guardada. También puedes mandarla antes con identify.
- user.metadataobjeto
- Datos libres asociados al usuario.
- typeenum
- STANDARD (ordinaria, por defecto) o SIMPLIFIED (simplificada). RECTIFYING y CREDIT_NOTE se rechazan con 400: las rectificativas tienen su propia ruta.
- seriesCodestring
- Serie en la que se numera la factura: el código de una serie que tu organización ha reservado a la aplicación (consúltalas con GET /external/v1/invoices/series) o DEFAULT para la serie de siempre del tipo. Mayúsculas y cifras, hasta 10 caracteres. Si lo omites, la serie por defecto de la aplicación para el tipo y, si no tiene, la de siempre. Ver «Series disponibles».
- recipientobjeto
- Datos fiscales del receptor que se imprimen en la factura. Obligatorio en la ordinaria; opcional en la simplificada (ver «Ordinaria o simplificada»).
- recipient.namestringobligatorio
- Nombre o razón social del receptor. Obligatorio si mandas el bloque.
- recipient.taxIdstring
- NIF o CIF. Obligatorio en facturas entre empresas. En una simplificada la convierte en cualificada y obliga a mandar la dirección completa.
- recipient.addressstring
- Dirección (calle y número). Obligatoria en la ordinaria y en la simplificada con NIF.
- recipient.citystring
- Ciudad. Obligatoria en la ordinaria y en la simplificada con NIF.
- recipient.postalCodestring
- Código postal. Obligatorio en la ordinaria y en la simplificada con NIF.
- recipient.countrystring
- País (mejor en castellano, por ejemplo «España»). Obligatorio en la ordinaria y en la simplificada con NIF.
- recipient.emailstring
- Correo del receptor.
- recipient.phonestring
- Teléfono del receptor.
- issueDatestring
- Fecha de expedición (AAAA-MM-DD). Si la omites, hoy en la zona horaria de tu organización. No puede ser futura ni anterior a la de la última factura ya expedida en la misma serie, y su año es el de la numeración: si no, 400 INVOICE_ISSUE_DATE_OUT_OF_ORDER sin numerar.
- dueDatestring
- Fecha de vencimiento (AAAA-MM-DD).
- taxSystemenum
- IVA, IGIC, IPSI, EXEMPT, INTERNATIONAL o EU_OSS. Si lo omites, se toma del régimen fiscal de tu organización (nunca EU_OSS). EU_OSS es el IVA del país del consumidor por la ventanilla única, que está en «Próximamente»: sus reglas están en Ventanilla única del IVA (OSS) y, mientras no esté disponible para tu organización, responde 403 FEATURE_COMING_SOON.
- notesstring
- Notas visibles al cliente (se imprimen en el PDF).
- discountPercentnumber
- Descuento global (de 0 a 100). Un valor mayor que cero junto con pricesIncludeTax: true responde 400 TAX_INCLUSIVE_GLOBAL_DISCOUNT_UNSUPPORTED.
- pricesIncludeTaxboolean
- Si es true, unitPrice y discount de cada línea son importes CON impuestos y el total de cada línea es exactamente lo cobrado. Si lo omites, los precios son sin impuestos.
- paymentobjeto
- Cobro que tu aplicación ya hizo fuera de UTILIA OS, por ejemplo con su propia pasarela. Con él, la factura queda cobrada por su total en el mismo acto.
- payment.methodenumobligatorio
- Obligatorio si mandas el bloque. CARD (una tarjeta cobrada con tu pasarela), TRANSFER, CASH, CHECK u OTHER. Las formas de la pasarela de UTILIA OS (STRIPE_*) no se admiten.
- payment.paidAtstring
- Fecha y hora del cobro (ISO 8601). No puede ser futura. Si la omites, el momento de la llamada.
- payment.referencestring
- Referencia del cobro en tu pasarela o en tu banco (por ejemplo, pi_...), hasta 200 caracteres. Queda registrada para la conciliación.
- consumerResidenceobjeto
- Residencia del consumidor final y su prueba. Se coteja con el sistema fiscal de la factura y no se imprime.
- consumerResidence.regionenumobligatorio
- Obligatorio si mandas el bloque. CANARIAS (IGIC), PENINSULA_BALEARES (IVA; con la ventanilla única, también EU_OSS en el régimen exterior), CEUTA_MELILLA, OTHER_EU (otro país de la Unión Europea; con la ventanilla única, EU_OSS) o NON_EU (fuera de la Unión Europea).
- consumerResidence.countryCodestring
- País en código ISO 3166-1 de dos letras. Obligatorio con OTHER_EU y NON_EU.
- consumerResidence.evidencestring
- Resumen de la prueba de residencia que conserva tu aplicación, por ejemplo «país de la tarjeta: ES; código postal de facturación: 38», hasta 500 caracteres. No envíes la dirección IP ni la dirección postal completa: basta con el resumen.
- consumerResidence.evidenceItemsarray
- Solo con EU_OSS, y obligatoria en ese caso (Próximamente): prueba estructurada de la ubicación del consumidor, de 1 a 10 elementos con type, countryCode y, si es España, region y thirdParty. Fuera de EU_OSS, 400 VALIDATION_ERROR. Ver Ventanilla única del IVA (OSS).
- metadataobjeto
- Datos libres asociados a la factura. Las claves que empiezan por external y que usa UTILIA OS están reservadas: no se pueden fijar.
- linesarrayobligatorio
- Líneas de la factura. Mínimo una.
- lines[].namestringobligatorio
- Concepto breve.
- lines[].descriptionstring
- Descripción extendida.
- lines[].quantitynumberobligatorio
- Cantidad (hasta 4 decimales).
- lines[].unitPricenumberobligatorio
- Precio unitario sin impuestos. Con pricesIncludeTax: true, precio con impuestos.
- lines[].taxTypeenumobligatorio
- Tipo de impuesto (por ejemplo, IVA_21, IGIC_7 o EXEMPT). Debe pertenecer al sistema fiscal de la factura. Con EU_OSS, todas las líneas son EU_VAT.
- lines[].vatRateClassenum
- Solo en líneas EU_VAT (Próximamente): clase del tipo de IVA del país del consumidor, STANDARD (por defecto), REDUCED, REDUCED_SECOND, SUPER_REDUCED o PARKING. El porcentaje lo resuelve y congela UTILIA OS. En otras líneas, 400 VALIDATION_ERROR.
- lines[].ossSupplyTypeenum
- Solo en líneas EU_VAT (Próximamente): SERVICES (por defecto) o GOODS (venta a distancia de bienes, solo en el régimen de la Unión). En otras líneas, 400 VALIDATION_ERROR.
- lines[].discountnumber
- Descuento en importe por línea. Con pricesIncludeTax: true, importe con impuestos.
- lines[].igicOperationTypeenum
- Solo para el régimen especial del comerciante minorista del IGIC: IGIC_RETAIL (venta de la actividad minorista, exenta; exige taxType EXEMPT) o IGIC_GENERAL (resto). Exige que tu organización tenga ese régimen declarado en su configuración fiscal.
- lines[].exemptionReasonenum
- Causa de la exención: EXEMPT_IGIC_RETAILER, EXEMPT_IGIC_INTERNAL, EXEMPT_EXPORT, EXEMPT_OTHER o EXEMPT_IGIC_SMALL_BUSINESS (régimen del pequeño empresario del IGIC). Obligatoria cuando taxType es EXEMPT con IGIC, salvo en un periodo del régimen del pequeño empresario, en el que UTILIA OS pone esa causa por ti. Decide la mención legal que se imprime.
- lines[].exemptionNotestring
- Explicación de la exención (máximo 300 caracteres). Obligatoria con EXEMPT_OTHER; se imprime en la mención legal de la factura.
- sendEmailboolean
- Decide si la factura sale por correo al emitirla y manda sobre el interruptor «Enviar las facturas por correo al emitirlas» de la aplicación en los dos sentidos: true la envía aunque esté apagado y false la retiene aunque esté encendido. Si lo omites, decide el interruptor. El envío ocurre después del cierre fiscal: un fallo de correo nunca tumba una factura ya numerada, y su resultado llega en emailDelivery (ver «El correo de la factura»). Enviar el correo requerirá el permiso crm:invoices:send: mientras dure la transición, si tu aplicación no lo tiene el correo sale igual y la respuesta lleva la cabecera X-Deprecation-Warning; pide ya ese permiso para no quedarte sin envíos cuando termine.
- idempotencyKeystring
- Clave de idempotencia (hasta 128 caracteres). Si llega la misma con el mismo cuerpo, se devuelve la factura original; con otro contenido, 409 BILLING_IDEMPOTENCY_CONFLICT. Si la primera petición todavía se está ejecutando, la repetición devuelve esa misma factura con issuanceDeliveryStatus: processing, nunca una segunda. Se compara el cuerpo tal como llega: mandar un campo con su valor por defecto (por ejemplo, "type": "STANDARD" o "seriesCode": "DEFAULT") cuenta como un cuerpo distinto del que lo omite. Repetir una clave ya emitida devuelve su factura aunque la serie se haya desactivado después.
Si el bloque user no trae taxId o billingAddress y el usuario
tampoco los tiene guardados, se toman del recipient que se imprime en
el documento y se escriben en su ficha. Lo que declare user manda
siempre, y un dato ya guardado nunca se pisa con el del receptor. Es
una red, no la vía principal: manda los datos fiscales con
identify en cuanto los tengas,
porque una factura emitida a un cliente sin identificador fiscal obliga
a rectificarla.
Ejemplo de petición
curl -X POST https://os.utilia.ai/api/external/v1/invoices \
-H "X-Api-Key: utl_live_..." \
-H "Content-Type: application/json" \
-d '{
"user": {
"externalId": "user_01HXYZ",
"email": "cliente@empresa.com",
"name": "Empresa de Canarias SL",
"taxId": "B76543210"
},
"recipient": {
"name": "Empresa de Canarias SL",
"taxId": "B76543210",
"address": "Avenida de Canarias 12",
"city": "Las Palmas",
"postalCode": "35001",
"country": "España"
},
"issueDate": "2026-04-19",
"dueDate": "2026-05-19",
"taxSystem": "IGIC",
"lines": [
{
"name": "Plan Premium mensual",
"quantity": 1,
"unitPrice": 49.95,
"taxType": "IGIC_7"
}
],
"sendEmail": true,
"idempotencyKey": "ord_01HXYZ-invoice"
}'Respuesta correcta (201)
{
"id": "ckinv1234567890",
"invoiceNumber": "202600042",
"displayNumber": "2026-00042",
"type": "STANDARD",
"seriesCode": "DEFAULT",
"taxSystem": "IGIC",
"consumerCountryCode": null,
"ossScheme": null,
"status": "SENT",
"legalMentions": [],
"originalInvoiceId": null,
"issuancePending": false,
"issuanceDeliveryStatus": "complete",
"issuanceMessage": "La factura está emitida y su entrega ha terminado.",
"emailDelivery": {
"status": "sent",
"message": "La factura se ha enviado por correo.",
"attempts": 1,
"lastAttemptAt": "2026-10-01T09:12:45.000Z",
"sentAt": "2026-10-01T09:12:46.000Z"
},
"cancellationPending": false,
"totalAmount": 53.45,
"paidAmount": 0,
"currency": "eur",
"issueDate": "2026-10-01T00:00:00.000Z",
"dueDate": "2026-10-08T00:00:00.000Z",
"pdfUrl": "/api/external/v1/invoices/ckinv1234567890/pdf?userId=user_01HXYZ",
"externalUserId": "user_01HXYZ",
"createdAt": "2026-10-01T09:12:44.000Z",
"idempotent": false,
"emailSent": true
}- invoiceNumberstringobligatorio
- Número registrado de la factura: AAAA00000 o PREFIJO-AAAA00000 según la serie (por ejemplo, T-202600001), sin guion. Es el de los libros registro y, si la factura lo lleva, el de su código QR. Guárdalo, búscalo y concilia con él.
- displayNumberstringobligatorio
- El número tal como se imprime en el PDF y se enseña en los correos y en el panel: invoiceNumber con un guion entre el año y el número de orden (T-202600001 se imprime T-2026-00001). Es solo presentación: para guardar y buscar, usa invoiceNumber.
- typeenumobligatorio
- STANDARD, SIMPLIFIED, RECTIFYING (rectificativa) o CREDIT_NOTE (abono emitido por tu equipo). Las facturas anteriores a este campo son STANDARD.
- seriesCodestringobligatorio
- Serie en la que se numeró: el código de una serie de tu aplicación o DEFAULT para la serie de siempre de su tipo (también en las rectificativas, que van siempre a la serie de rectificativas).
- taxSystemenumobligatorio
- Sistema impositivo del documento, EU_OSS incluido. Una rectificativa conserva el de su original.
- consumerCountryCodestring | nullobligatorio
- Estado miembro de consumo (ISO 3166-1 alfa-2): el del consumidor de otro país de la Unión y, en EU_OSS, el país cuyo IVA se aplica. Nulo en el resto.
- ossSchemeenum | nullobligatorio
- Solo en EU_OSS: régimen de la ventanilla única con que se emitió, OSS_UNION_SCHEME u OSS_NON_UNION_SCHEME. Nulo en el resto.
- legalMentionsstring[]obligatorio
- Menciones legales impresas, en su orden. Las calcula UTILIA OS a partir del tipo de factura y de las causas de exención de sus líneas; tu aplicación no las fija.
- originalInvoiceIdstring | nullobligatorio
- Factura que corrige este documento. Nulo salvo en rectificativas y abonos.
- pricesIncludeTaxboolean
- Solo viaja, y en true, si la factura se creó con pricesIncludeTax: true. Entonces el unitPrice de las líneas es el precio sin impuestos que calculó UTILIA OS.
- paymentRegisteredboolean
- Solo viaja si mandaste payment. true: el cobro quedó registrado, en el acto o después. false: la factura está emitida pero el registro del cobro falló (o la emisión se cortó antes de llegar a registrarlo); complétalo con POST /external/v1/invoices/:id/mark-paid o desde la ficha de la factura en UTILIA OS, y en las lecturas siguientes pasa a true. Repetir la clave de idempotencia no lo reintenta.
- issuancePendingboolean
- true solo mientras la emisión está en curso (processing) o si se interrumpió antes de terminar su cierre fiscal (review_required). Un correo o un cobro que no salieron no la dejan pendiente.
- issuanceDeliveryStatusenum
- Estado de la emisión: processing, review_required o complete. Ver «Estado de la emisión». Viaja en las facturas que emite la API externa.
- issuanceMessagestring
- Qué falta, si falta algo, y cómo completarlo sin duplicar la factura ni sus envíos, en castellano y listo para tu registro.
- emailDeliveryobjeto
- Solo viaja si el correo se pidió: con sendEmail: true o, si lo omites, con el interruptor de la aplicación encendido. Dice si la factura ha llegado al cliente por correo, por qué no y qué hacer. Se actualiza solo. Ver «El correo de la factura».
- emailSentboolean
- Resumen de emailDelivery en un booleano: true si el correo salió. Viaja cuando tocaba enviar, también en las repeticiones con la misma clave. En falso, la factura SÍ está emitida y numerada y solo falta el correo: mira emailDelivery.status para saber si lo reintenta UTILIA OS (retrying) o tienes que enviarla tú (failed o withheld). No la vuelvas a crear nunca.
- pdfUrlstringobligatorio
- Ruta relativa, con el userId, para descargar el PDF desde tu servidor con la misma clave de API. No es un enlace para tu usuario final: para eso está el enlace público.
- idempotentbooleanobligatorio
- Indica si la respuesta es una factura ya existente, reutilizada por la clave de idempotencia.
displayNumber, issuanceDeliveryStatus, issuanceMessage y
emailDelivery vuelven en todas las lecturas de la factura (el detalle,
el listado y las respuestas de las acciones), con su valor de ese
momento. emailSent e idempotent solo los trae la respuesta del alta.
El PDF, los correos y el panel presentan el número con un guion entre
el año y el número de orden (T-2026-00001): es displayNumber. El
número registrado, el de los libros registro y, si la factura lo lleva,
el de su código QR, va sin guion (T-202600001): es invoiceNumber, y
es el que debes guardar, buscar y conciliar. El guion solo es
presentación.
El PDF de la API externa no es un enlace público
pdfUrl exige la cabecera X-Api-Key y no debe salir de tu servidor.
Para entregar la factura a tu usuario final, emite el enlace público con
POST /external/v1/invoices/:id/public-link.
Precios con impuestos incluidos
Si tu aplicación cobra un precio cerrado, por ejemplo 39,99 €, manda
pricesIncludeTax: true y ese precio en unitPrice. UTILIA OS busca la
base exacta al céntimo para que el total de la línea sea exactamente lo
cobrado:
| Línea | Base | Cuota | Total |
|---|---|---|---|
39,99 con IGIC_7 | 37,37 | 2,62 | 39,99 |
39,99 con EXEMPT | 39,99 | — | 39,99 |
En las líneas exentas o no sujetas, la base es el propio importe. Si un
importe no tiene una base exacta al céntimo con su tipo, la respuesta
es 422 TAX_INCLUSIVE_PRICE_NOT_REPRESENTABLE con el número de línea en
lineNumber (empieza en 1): ajusta un céntimo o usa cantidad 1. Nunca
se emite una factura cuyo total difiera del cobrado.
Una factura que ya cobraste con tu pasarela
Si tu aplicación cobra con su propia pasarela (por ejemplo, su cuenta
de Stripe) y usa UTILIA OS solo para facturar, manda el bloque
payment. La factura se emite y queda cobrada por su total en el
mismo acto, y si se envía por correo sale con la plantilla de factura
pagada: tu cliente recibe un único correo.
Si el registro del cobro falla, la factura ya está emitida y su emisión
está completa: paymentRegistered llega en false e
issuanceDeliveryStatus en complete. Para no pedirle a tu cliente que
pague algo que ya pagó, el correo no sale (emailDelivery.status en
withheld, con reason: PAYMENT_NOT_REGISTERED). Registra el cobro con
mark-paid
(o tu equipo, con Registrar cobro en la ficha de la factura):
paymentRegistered pasa a true y después la envías con send.
Repetir la clave de idempotencia no lo reintenta. Un cobro sin registrar
no impide rectificar ni anular la factura. Sin payment, la factura
queda pendiente de cobro, como hasta ahora.
Residencia del consumidor
Con consumerResidence dejas constancia de dónde reside el consumidor
y de cómo lo sabes. Es tu aplicación quien lo conoce: UTILIA OS no lo
deduce si no lo mandas. Si lo mandas, se coteja con el sistema fiscal de
la factura:
CANARIASexigeIGIC.PENINSULA_BALEARESexigeIVA.CEUTA_MELILLA,OTHER_EUyNON_EUno admitenIGIC.
Si no cuadra, la respuesta es 400 TAX_SYSTEM_RESIDENCE_MISMATCH. La
residencia se guarda con la factura, no se imprime y no se devuelve en
metadata. Con un consumidor de otro país de la Unión (OTHER_EU), la
respuesta trae su país en consumerCountryCode.
Cuando la ventanilla única del IVA
esté disponible para tu organización (hoy está en «Próximamente») y una
venta a un consumidor de la Unión ya tribute en el país del consumidor,
una factura con IVA español a ese consumidor se rechazará con
400 OSS_THRESHOLD_EXCEEDED u OSS_DESTINATION_VAT_REQUIRED. Para las
demás organizaciones no cambia nada.
Régimen del pequeño empresario del IGIC (REPEP)
Si tu organización es un autónomo canario y tiene declarado el Régimen especial del pequeño empresario o profesional (REPEP) en Finanzas, Ajustes, Fiscal, Regímenes especiales, sus ventas con IGIC dentro de un periodo del régimen están exentas:
- Manda las líneas con
taxType: "EXEMPT"y sinexemptionReason. UTILIA OS les pone la causaEXEMPT_IGIC_SMALL_BUSINESS(«Pequeño empresario (franquicia fiscal)») y la factura lleva la mención «Exención franquicia fiscal». - Una línea con cuota de IGIC, también
IGIC_0, responde400 IGIC_SMALL_BUSINESS_TAXED_LINEconlineNumber. El tipo cero no es una exención. - Solo afecta a facturas con
taxSystem: "IGIC". Las ventas a consumidores de Península y Baleares llevan IVA y no cambian; mandar la causa del REPEP en una factura que no es IGIC responde400 IGIC_SMALL_BUSINESS_REQUIRES_IGIC. - Mandar la causa con una fecha fuera de cualquier periodo del régimen responde
400 IGIC_SMALL_BUSINESS_NOT_ACTIVE.
Qué es el régimen, quién puede declararlo y qué cambia en los modelos está en Impuestos.
Ejemplo completo: simplificada de 39,99 € en el REPEP, cobrada en el acto
Un consumidor residente en Tenerife paga 39,99 € con la tarjeta en la pasarela de tu aplicación. Tu organización está en el REPEP.
curl -X POST https://os.utilia.ai/api/external/v1/invoices \
-H "X-Api-Key: utl_live_..." \
-H "Content-Type: application/json" \
-d '{
"type": "SIMPLIFIED",
"user": { "externalId": "user_01HXYZ", "email": "ana@example.com" },
"taxSystem": "IGIC",
"pricesIncludeTax": true,
"lines": [
{ "name": "Plan Básico mensual", "quantity": 1, "unitPrice": 39.99, "taxType": "EXEMPT" }
],
"payment": { "method": "CARD", "reference": "pi_3QabcDEF" },
"consumerResidence": {
"region": "CANARIAS",
"evidence": "Dirección de facturación y tarjeta en Santa Cruz de Tenerife."
},
"sendEmail": true,
"idempotencyKey": "pedido-4471"
}'Con la línea exenta, pricesIncludeTax no cambia nada (la base es el
total), pero conviene mandarlo si tu aplicación siempre trabaja con
precios cerrados: si algún día la venta lleva cuota, el total seguirá
siendo el cobrado.
{
"id": "cksimp1234567890",
"invoiceNumber": "T-202600001",
"displayNumber": "T-2026-00001",
"type": "SIMPLIFIED",
"seriesCode": "DEFAULT",
"status": "PAID",
"legalMentions": [
"Factura simplificada (RD 1619/2012 art. 7)",
"Exención franquicia fiscal"
],
"pricesIncludeTax": true,
"paymentRegistered": true,
"originalInvoiceId": null,
"issuancePending": false,
"issuanceDeliveryStatus": "complete",
"issuanceMessage": "La factura está emitida y su entrega ha terminado.",
"emailDelivery": {
"status": "sent",
"message": "La factura se ha enviado por correo.",
"attempts": 1,
"lastAttemptAt": "2026-10-13T09:30:13.000Z",
"sentAt": "2026-10-13T09:30:14.000Z"
},
"totalAmount": 39.99,
"paidAmount": 39.99,
"currency": "eur",
"issueDate": "2026-10-13T00:00:00.000Z",
"dueDate": null,
"pdfUrl": "/api/external/v1/invoices/cksimp1234567890/pdf?userId=user_01HXYZ",
"externalUserId": "user_01HXYZ",
"createdAt": "2026-10-13T09:30:12.000Z",
"idempotent": false,
"emailSent": true
}El PDF imprime «T-2026-00001» como número, «Consumidor final» como destinatario, sin dirección, «IGIC: exento» en lugar de un tipo y la mención «Exención franquicia fiscal». Si más adelante devuelves el dinero, emite su rectificativa con Facturas rectificativas.
Reintentar sin duplicar la factura
Emitir una factura hace varias cosas en el mismo paso (numerarla,
registrarla, generar su PDF y, si lo pides, registrar el cobro y enviar
el correo), así que la respuesta puede tardar varios segundos. Pon a tu
cliente HTTP un tiempo de espera de al menos 30 segundos para
POST /external/v1/invoices: uno más corto corta peticiones que sí
terminan.
Si aun así se corta la conexión, no sabes si la factura llegó a
emitirse. Repite la petición con la misma idempotencyKey y el
mismo cuerpo, nunca con una clave nueva: durante 24 horas, UTILIA OS
reconoce la clave y no emite otra. Si la primera petición todavía se
está ejecutando, la repetición devuelve esa misma factura con
issuanceDeliveryStatus: processing; consulta de nuevo con la misma
clave hasta que llegue complete.
Reintentar con la misma clave de idempotencia
Participan: Tu servidor, UTILIA OS.
De Tu servidor a UTILIA OS:
POST /api/external/v1/invoices
Con idempotencyKey: ord_01HXYZ-invoice.Nota en UTILIA OS:
Numera la factura, la emite y responde, pero la respuesta se pierde por el camino.De Tu servidor a UTILIA OS:
POST /api/external/v1/invoices
La misma clave y el mismo cuerpo.De UTILIA OS a Tu servidor:
La misma factura, con idempotent: true (respuesta)
No se emite ninguna factura nueva. Si la primera ejecución sigue en marcha, llega con issuanceDeliveryStatus: processing.
¿Qué pasa si repites una clave de idempotencia?
¿Usaste esa idempotencyKey en las últimas 24 horas?
No:
Factura nueva
idempotent: false
Se numera y se emite otra factura.Sí:
¿Envías el mismo cuerpo?
Sí:
La misma factura
idempotent: true
No se emite ninguna factura nueva.No:
Conflicto
409 BILLING_IDEMPOTENCY_CONFLICT
Una clave sirve para una sola factura. Usa una nueva para otra factura.
Estado de la emisión
issuanceDeliveryStatus dice si la emisión ha terminado. Habla solo del
cierre fiscal (el número, el sello, el registro y los efectos del
documento, como su PDF y su código QR), no de la entrega:
issuanceDeliveryStatus | Qué significa | Qué haces |
|---|---|---|
processing | La emisión sigue en curso. issuancePending llega en true. | Repite la misma petición, con la misma clave, en unos segundos. No crees otra factura. |
review_required | La ejecución se interrumpió antes de terminar el cierre fiscal. issuancePending llega en true. | Lo revisa el equipo de tu organización en la ficha de la factura, con el botón Dar por revisada. Hasta entonces la factura no se puede rectificar ni anular. Conserva la factura y la clave: repetir la petición no reemite nada ni envía correos. |
complete | La factura está emitida. | Mira emailDelivery y paymentRegistered para saber cómo fue la entrega. |
Un correo que no sale o un cobro del bloque payment que no se registra
no dejan la emisión pendiente: la factura queda complete, y su
resultado viaja aparte, en emailDelivery y paymentRegistered, para
completarlo sin tocar la factura. Tampoco impiden rectificarla ni
anularla.
Cambio del 19 de octubre de 2026
Hasta esa fecha, un correo que no salía o un cobro que no se registraba
dejaban la factura en review_required para siempre, y su rectificativa
y su anulación respondían 409. Si tu integración usaba
issuanceDeliveryStatus: review_required para detectar un correo
fallido, lee ahora emailDelivery. Las facturas anteriores que estaban
en revisión solo por el correo o por el cobro se leen ya como
complete, con el resultado del correo en emailDelivery y el del
cobro en paymentRegistered.
Dar por revisada está en el aviso «Emisión pendiente de revisión» de la ficha de la factura, en Finanzas › Facturas, necesitas entrar con tu cuenta, y lo ve quien tiene los permisos «Editar aplicaciones externas» y «Emitir facturas». Solo se acepta si la factura tiene número y su PDF original está generado y verificado; no reemite ni envía nada y queda en el registro de auditoría con el nombre de quien lo hizo. Después, la aplicación ya puede rectificarla o anularla repitiendo su petición. La ruta del panel que usa está en Panel de aplicaciones externas.
El correo de la factura
Si pides el correo (sendEmail: true, o sin sendEmail con el
interruptor de la aplicación encendido), UTILIA OS intenta enviarla
dentro de la misma petición, con la plantilla, el remitente y el PDF de
tu organización. El destinatario es el contacto de facturación
principal del cliente del CRM; si no hay, el correo del usuario
(user.email) y, en último lugar, el del destinatario de la factura
(recipient.email). El resultado llega en emailDelivery:
{
"emailDelivery": {
"status": "retrying",
"reason": "PDF_NOT_READY",
"message": "Todavía no se ha enviado por correo porque su PDF original se estaba terminando de preparar. UTILIA la enviará sola en unos minutos; no hace falta que la reenvíes.",
"attempts": 1,
"lastAttemptAt": "2026-10-19T10:00:09.000Z"
}
}- statusenumobligatorio
- sent, retrying, failed o withheld (ver la tabla siguiente).
- reasonenum
- Motivo estable cuando no se ha enviado. No viaja con sent.
- messagestringobligatorio
- Qué ha pasado y qué hacer, en castellano y listo para mostrar a tu equipo o a tu soporte.
- attemptsnumber
- Intentos de envío hechos hasta ahora.
- lastAttemptAtstring
- Último intento, en ISO 8601.
- sentAtstring
- Momento en que salió, en ISO 8601. Solo con sent.
status | Qué significa | Qué haces |
|---|---|---|
sent | El correo salió: al emitirla, en un reintento o porque alguien la envió después desde la ficha o con POST /send. | Nada. |
retrying | Todavía no ha salido por un fallo pasajero y UTILIA OS la reenvía sola. | Espera. No la reenvíes ni la vuelvas a crear. |
failed | No se ha podido enviar. | Envíala con POST /external/v1/invoices/:id/send o desde su ficha, después de resolver el motivo. |
withheld | No se ha enviado a propósito. | Resuelve el motivo y envíala con send. |
reason | status | Qué ha pasado |
|---|---|---|
PDF_NOT_READY | retrying | El PDF original de la factura se estaba terminando de preparar. |
STORAGE_UNAVAILABLE | retrying | El almacén de documentos no respondía. |
MAIL_SERVER_UNAVAILABLE | retrying | El servidor de correo no respondía. |
SEND_QUOTA_EXCEEDED | retrying | La aplicación agotó su cupo de 100 envíos por hora, el mismo que comparte con POST /send. Sale sola en cuanto haya cupo. |
SEND_FAILED | failed | El envío falló de forma definitiva, por ejemplo porque el servidor de salida lo rechazó. |
RETRIES_EXHAUSTED | failed | Fallaron todos los reintentos automáticos. |
NO_RECIPIENT | failed | No hay ninguna dirección a la que enviarla. Registra un contacto de facturación del usuario y envíala con send. |
INTERRUPTED | failed | La emisión se cortó mientras se enviaba y no consta si salió. Comprueba el historial de comunicaciones de la factura antes de reenviarla. |
SEND_SCOPE_MISSING | withheld | La aplicación no tiene crm:invoices:send y el envío venía del interruptor. Cuando se lo concedan, envíala con send. |
PAYMENT_NOT_REGISTERED | withheld | El cobro del bloque payment no se registró, y el correo pediría pagar una factura ya pagada. Registra el cobro con mark-paid y envíala después. |
Cómo reintenta UTILIA OS un correo en retrying:
- Dentro de la petición de alta espera al PDF original unos 8 segundos, como mucho. Si no está listo, no retiene la respuesta: el correo queda en
retrying. - Si el fallo fue del PDF, del almacén o del servidor de correo, hace un reintento rápido a los 45 segundos, más o menos.
- Después lo recoge la recuperación de envíos automáticos, que pasa cada 10 minutos, hasta 12 intentos en total (unas dos horas).
- Si se agotan,
emailDeliverypasa afailedconRETRIES_EXHAUSTEDy la persona que figura como creadora de la factura (la persona responsable de la aplicación cuando se emitió) recibe en UTILIA OS el aviso «Factura sin enviar».
Cada intento, y también cada decisión de no enviarla, queda en el
bloque Comunicaciones con el cliente de la ficha de la factura, como
«Factura enviada automáticamente», con su resultado. Si alguien la envía
mientras tanto desde la ficha o con POST /send, emailDelivery pasa a
sent y el reintento automático se detiene: la factura nunca sale dos
veces por esta vía. Mientras la emisión está en processing,
emailDelivery no viaja.
Para ensayar el correo sin emitir nada, POST /external/v1/invoices/validate
dice en preview.email si saldría y a qué dirección: ver
Probar la facturación sin emitir facturas.
Errores al crear
403 MODULE_NOT_ENABLED: el plan de tu organización no incluye el aplicativo Finanzas. Es una decisión comercial, no un fallo técnico: no reintentes.403 INSUFFICIENT_SCOPE: la aplicación no tiene concedidocrm:invoices:writeocrm:invoices:issue. La creación exige los dos, porque crea y emite en el mismo paso.403 BILLING_NOT_ENABLED: la facturación de la aplicación está apagada. La enciende un Super Administrador con Activar la facturación, en Dinero › Facturación de la ficha de la aplicación. Para descubrirlo antes de la primera factura real,POST /external/v1/invoices/validatelo devuelve como bloqueo, y el Resumen y la pestaña Pruebas de la aplicación lo marcan como paso pendiente.403 BILLING_AMOUNT_EXCEEDS_LIMIT: el total supera el tope por factura configurado para la aplicación.409 BILLING_IDEMPOTENCY_CONFLICT: la clave de idempotencia ya se usó con otro contenido.400 INVOICE_SERIES_NOT_AVAILABLE: la serie deseriesCodeno existe o no es de tu aplicación. El mensaje es el mismo en los dos casos.400 INVOICE_SERIES_TYPE_MISMATCH: la serie es de otro tipo de documento (una de ordinarias para una simplificada, o al revés).409 INVOICE_SERIES_INACTIVE: la serie está desactivada. Usa otra o pide a tu organización que la reactive.400 INVOICE_ISSUE_DATE_OUT_OF_ORDER:issueDatees futura o anterior a la de la última factura de la misma serie. LleganissueDateytodayolastIssueDateyseriesCode.400 INVOICE_RECIPIENT_REQUIRED: factura ordinaria sinrecipient.400 INVOICE_RECIPIENT_INCOMPLETE: factura ordinaria con el destinatario incompleto. Los campos que faltan llegan enmissingFields.400 SIMPLIFIED_RECIPIENT_INCOMPLETE: simplificada con NIF sin el resto de datos del destinatario. Los que faltan llegan enmissingFields.422 SIMPLIFIED_INVOICE_AMOUNT_EXCEEDED: simplificada por encima de 400 € impuestos incluidos. Emite una ordinaria.422 TAX_INCLUSIVE_PRICE_NOT_REPRESENTABLE: conpricesIncludeTax, el importe de la línealineNumberno tiene base exacta al céntimo.400 TAX_INCLUSIVE_GLOBAL_DISCOUNT_UNSUPPORTED:pricesIncludeTaxcon undiscountPercentmayor que cero.400 TAX_SYSTEM_RESIDENCE_MISMATCH: la residencia del consumidor no cuadra con el sistema fiscal.400 IGIC_SMALL_BUSINESS_TAXED_LINE,IGIC_SMALL_BUSINESS_REQUIRES_IGICoIGIC_SMALL_BUSINESS_NOT_ACTIVE: reglas del régimen del pequeño empresario del IGIC (ver arriba).403 FEATURE_COMING_SOON: la petición lleva algo de la ventanilla única del IVA, que todavía no está disponible para tu organización. No es un bloqueo de plan: no lo reintentes.400 OSS_*: reglas de la ventanilla única del IVA, que está en «Próximamente»; antes,403 FEATURE_COMING_SOON.400 VALIDATION_ERROR: uno o más campos no cumplen las restricciones.
Series disponibles
Sin hacer nada, las facturas ordinarias de tu aplicación se numeran en
la serie general de tu organización, intercaladas con las que emite el
equipo, y las simplificadas en T-. Si quieres que las de tu aplicación
vayan aparte (por ejemplo, APP-202600001), una persona de tu
organización con el permiso «Editar organización» crea una serie para
la aplicación en Ajustes › Organización, necesitas entrar con tu cuenta,
pestaña Facturas, bloque Series de facturación, y puede fijarla
como serie por defecto de la aplicación en su pantalla Facturación.
Tu aplicación no crea ni cambia series con la clave de API: solo las
consulta y elige entre las suyas.
/api/external/v1/invoices/seriesSeries en las que la aplicación puede numerar sus facturas: la de siempre de cada tipo, las que tu organización le ha reservado y, solo informativa, la de rectificativas. Permiso: crm:invoices:read.
Respuesta (200)
{
"fiscalYear": 2026,
"series": [
{ "code": "DEFAULT", "documentType": "STANDARD", "prefix": null, "example": "202600001", "description": null, "isAppDefault": false, "selectable": true },
{ "code": "APP", "documentType": "STANDARD", "prefix": "APP", "example": "APP-202600001", "description": "Facturas de la aplicación de reservas", "isAppDefault": true, "selectable": true },
{ "code": "DEFAULT", "documentType": "SIMPLIFIED", "prefix": "T", "example": "T-202600001", "description": null, "isAppDefault": true, "selectable": true },
{ "code": "DEFAULT", "documentType": "RECTIFYING", "prefix": "R", "example": "R-202600001", "description": null, "isAppDefault": false, "selectable": false }
]
}- fiscalYearnumberobligatorio
- Año en curso en la zona horaria de tu organización.
- series[].codestringobligatorio
- El valor que mandas en seriesCode. DEFAULT es la serie de siempre de su tipo.
- series[].documentTypeenumobligatorio
- STANDARD (ordinarias), SIMPLIFIED (simplificadas) o RECTIFYING (la de rectificativas, solo informativa).
- series[].prefixstring | nullobligatorio
- Prefijo impreso delante del número. La serie general puede no tener prefijo.
- series[].examplestringobligatorio
- El primer número del año con el formato real de la serie. No es el siguiente número: la respuesta no lo da, porque revelaría cuántas facturas emite tu organización.
- series[].descriptionstring | nullobligatorio
- Motivo de la serie que indicó tu organización al crearla.
- series[].isAppDefaultbooleanobligatorio
- Es la que se usa para su tipo cuando el alta no trae seriesCode: la serie por defecto de la aplicación o, si no tiene, la de siempre.
- series[].selectablebooleanobligatorio
- Se puede elegir en seriesCode. La de rectificativas llega en false: las rectificativas van siempre a ella, sin elegirla.
Solo aparecen las series activas reservadas a tu aplicación: nunca las de otra aplicación ni las que el equipo usa en sus facturas.
Qué serie lleva cada factura
- Si mandas
seriesCode, esa serie.DEFAULTfuerza la de siempre aunque la aplicación tenga una por defecto. - Si no, la serie por defecto de la aplicación para el tipo (ordinaria o simplificada).
- Si no tiene, la de siempre: la general para las ordinarias y
T-para las simplificadas.
La serie tiene que ser de tu aplicación (400 INVOICE_SERIES_NOT_AVAILABLE),
del mismo tipo que la factura (400 INVOICE_SERIES_TYPE_MISMATCH) y
estar activa (409 INVOICE_SERIES_INACTIVE). Todo se comprueba antes
de numerar: un rechazo nunca consume un número ni deja hueco en la
serie. Cada serie lleva su propia numeración correlativa, que empieza de
nuevo cada año, y la respuesta dice en seriesCode en cuál se numeró.
Las rectificativas van siempre a la serie de rectificativas (R-),
aunque la factura original esté en una serie de tu aplicación. Las
suscripciones también admiten seriesCode: ver
Suscripciones.
Fecha de expedición
Con la serie, issueDate queda acotada para que la numeración nunca
retroceda:
- No puede ser futura en la zona horaria de tu organización.
- No puede ser anterior a la de la última factura ya expedida en la misma serie.
- Su año es el de la numeración: una factura con fecha de 2026 lleva un número de 2026.
Si no se cumple, la respuesta es 400 INVOICE_ISSUE_DATE_OUT_OF_ORDER,
sin numerar, con issueDate y, según el caso, today o lastIssueDate
y seriesCode. Si omites issueDate, se usa el día de hoy en la zona
horaria de tu organización.
Listar facturas
/api/external/v1/invoicesLista paginada de facturas de la aplicación, con filtros opcionales por usuario, estado, tipo y serie. Permiso: crm:invoices:read.
Parámetros de consulta
- userIdstring
- Filtra por externalId del usuario.
- statusenum
- DRAFT, ISSUED, SENT, PAID, PARTIALLY_PAID, OVERDUE, CANCELLED, DISPUTED, OVERDUE_UNCOLLECTABLE, REFUNDED, PARTIALLY_REFUNDED o RECTIFIED.
- typeenum
- STANDARD, SIMPLIFIED, RECTIFYING o CREDIT_NOTE.
- seriesCodestring
- Código de una serie de tu aplicación o DEFAULT (las series de siempre de cada tipo; combínalo con type para acotar).
- fromDatedate
- Fecha de emisión mínima (AAAA-MM-DD).
- toDatedate
- Fecha de emisión máxima (AAAA-MM-DD).
- pageinteger
- Página (por defecto, 1).
- limitinteger
- Elementos por página (por defecto 20, máximo 100).
Respuesta (200)
{
"invoices": [
{
"id": "inv-uuid",
"invoiceNumber": "202600001",
"displayNumber": "2026-00001",
"type": "STANDARD",
"seriesCode": "DEFAULT",
"status": "PAID",
"issuancePending": false,
"issuanceDeliveryStatus": "complete",
"issueDate": "2026-04-19T00:00:00.000Z",
"dueDate": "2026-05-19T00:00:00.000Z",
"totalAmount": 53.45,
"paidAmount": 53.45,
"currency": "eur",
"pdfUrl": "/api/external/v1/invoices/inv-uuid/pdf?userId=user_01HXYZ",
"externalUserId": "user_01HXYZ"
}
],
"pagination": {
"page": 1,
"limit": 20,
"total": 1,
"totalPages": 1
}
}Detalle de factura
/api/external/v1/invoices/:idDatos completos de una factura: líneas, desglose de impuestos, receptor y rectificativas. Permiso: crm:invoices:read.
Parámetros
- idpathobligatorio
- Identificador de la factura en UTILIA OS.
- userIdqueryobligatorio
- externalId del usuario propietario.
Además de los campos de la respuesta del alta, el detalle trae:
- lines[].exemptionReasonenum | nullobligatorio
- Causa de la exención de la línea, o nulo si no está exenta. EXEMPT_IGIC_SMALL_BUSINESS es el régimen del pequeño empresario del IGIC.
- lines[].exemptbooleanobligatorio
- true en líneas exentas o no sujetas, que no repercuten cuota. Úsalo en lugar de taxRate: un tipo cero no es una exención.
- lines[].vatRateClass / lines[].ossSupplyTypeenum | nullobligatorio
- Solo en líneas EU_VAT de la ventanilla única: clase del tipo y servicios o bienes. En ellas, taxRate es el tipo del país del consumidor congelado al emitir. Nulos en el resto.
- taxes[].vatRateClassenum | nullobligatorio
- Solo en tramos EU_VAT: clase del tipo del tramo. Nulo en el resto.
- rectificationsarrayobligatorio
- Rectificativas de la factura, de la más antigua a la más reciente, con id, invoiceNumber, displayNumber (el número impreso, con guion entre el año y el número de orden), issueDate, totalAmount (negativo), rectificationCode y status. Vacía si no tiene o si el documento es a su vez una rectificativa.
- effectiveTotalnumber
- Total vigente: el de la factura más el de sus rectificativas emitidas, que restan. Solo en facturas que no son rectificativas ni abonos.
- rectificationCodeenum
- Solo en rectificativas y abonos: R1, R2, R3, R4 o R5. Las que emite la API externa son R1 o R5.
- rectificationTypeenum
- Solo en rectificativas y abonos: DIFFERENCE (por diferencias) o COMPLETE (sustitución, solo desde UTILIA OS).
En una simplificada sin destinatario, recipientName es «Consumidor
final» y la dirección, la ciudad y el código postal llegan con un guion.
Errores del detalle
403 INSUFFICIENT_SCOPE: la aplicación no tiene concedidocrm:invoices:read.404 EXTERNAL_USER_NOT_FOUND: no hay ningún usuario de la aplicación con eseuserId.404 INVOICE_NOT_ACCESSIBLE: la factura no existe, es de otra aplicación o no es de ese usuario. Es siempre la misma respuesta, para no revelar si la factura existe.
Descargar PDF
/api/external/v1/invoices/:id/pdfPDF fiscal de la factura (application/pdf). Permiso: crm:invoices:read.
Parámetros
- idpathobligatorio
- Identificador de la factura.
- userIdqueryobligatorio
- externalId del usuario propietario.
Devuelve el binario con Content-Type: application/pdf y Content-Disposition: attachment; filename="factura-...pdf".
Anular factura
/api/external/v1/invoices/:id/cancelAnula una factura ordinaria o simplificada emitida. Permiso: crm:invoices:cancel, que solo concede un Super Administrador.
Anular es para una factura que no debió emitirse (un duplicado, un error). Si la venta existió y devuelves el dinero, no la anules: emite una rectificativa.
Cuerpo
- reasonstring
- Motivo de la anulación. Se guarda en las notas internas de la factura.
userId (el externalId del propietario) va como parámetro de consulta, igual que en el detalle.
Errores de la anulación
403 INSUFFICIENT_SCOPE: la aplicación no tiene concedidocrm:invoices:cancel.409 INVOICE_STATE_INVALID: no se pueden anular borradores.409 INVOICE_ALREADY_CANCELLED: ya estaba anulada.409 BILLING_IDEMPOTENCY_CONFLICT: la emisión sigue en curso (repite la anulación en unos segundos), su cierre fiscal se interrumpió y tu equipo tiene que darla por revisada antes (ver Estado de la emisión) o una anulación anterior aún no ha terminado. Un correo o un cobro del alta que no salieron no impiden anularla.
Estadísticas del usuario
/api/external/v1/invoices/statsTotales de facturación de un usuario externo. Permiso: crm:invoices:read.
Parámetros de consulta
- userIdstringobligatorio
- externalId del usuario.
Respuesta (200)
{
"total": 12,
"paid": 8,
"pending": 3,
"overdue": 1,
"totalAmount": 641.40,
"totalPaid": 427.60,
"totalPending": 213.80,
"currency": "eur"
}- totalnumberobligatorio
- Total de facturas emitidas a ese usuario externo.
- paidnumberobligatorio
- Facturas en estado PAID.
- pendingnumberobligatorio
- Facturas en estado ISSUED, SENT o PARTIALLY_PAID.
- overduenumberobligatorio
- Facturas en estado OVERDUE.
- totalAmountnumberobligatorio
- Suma del importe total facturado.
- totalPaidnumberobligatorio
- Suma del importe ya cobrado.
- totalPendingnumberobligatorio
- Diferencia entre lo facturado y lo cobrado (nunca negativa).
- currencystringobligatorio
- Divisa de tu organización en minúsculas (por ejemplo,
eur).
Cabeceras comunes
- X-Api-Keyheaderobligatorio
- Clave de API de la aplicación externa.
- X-Request-Idheader
- Identificador para seguir la petición; UTILIA OS lo devuelve en la respuesta.
- Content-Typeheaderobligatorio
- application/json en las peticiones con cuerpo.
Límite de uso
Todos los endpoints de este grupo comparten un límite de 60 peticiones por minuto por clave, además del límite general de la clave (1.000 peticiones por hora). Al superarlo, la respuesta es 429 Too Many Requests con la cabecera Retry-After, que indica los segundos que hay que esperar.
Siguiente paso
- Acciones sobre una facturaEnviar, cobrar, marcar pagada, devolver y enlace público.
- Facturas rectificativasDocumentar una devolución o un contracargo que deja la venta sin efecto.
- SuscripcionesCuotas que se generan, envían y cobran solas cada periodo.
- Guía de facturaciónEl recorrido completo, del alta del usuario al cobro recurrente.