Faxtal
Facturas

Facturas emitidas

Una factura emitida tiene número y fecha, y ya es definitiva. Lo normal es crearla como borrador y emitirla. La importación sirve para dar de alta facturas que ya emitiste con otro programa.

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, listar, validar, ver eventos, descargar documentos y PDFinvoices:read
Añadir y eliminar documentosinvoices:write
Emitir, importar, anular y eliminar importadasinvoices:issue

Sin el scope necesario, la API responde 403 con el código scope_missing.

Estados

statusSignificado
draftBorrador. Ver Borradores.
issuedEmitida.
sentEmitida y enviada por email. Ver Envío por email.
cancelledAnulada.
queuedReservada por una emisión en bloque iniciada desde la aplicación.

Emitir un borrador

POST /api/v1.1/issued-invoices/{invoice_id}/issue

El borrador lo creas antes con PUT /api/v1.1/drafts. El cuerpo es opcional:

CampoDescripción
invoice_numberNúmero con el que se emite, si lo numera tu programa. Máximo 60 caracteres. Sin él, se asigna el siguiente número de la serie. Ver Emitir con el número de tu programa.

Sin cuerpo:

curl -X POST "https://app.faxtal.com/api/v1.1/issued-invoices/00000000-0000-0000-0000-000000000001/issue" \
  -H "X-API-Key: fctXXXXXXXX_YYYYYYYYYYYYYYYY"

Qué hace la emisión:

  1. Comprueba que la empresa esté verificada.
  2. Valida el borrador. Si tiene errores, no emite y el borrador sigue en draft.
  3. Asigna la fecha del día y el número: el siguiente de la serie o el invoice_number que envías. El número sigue la plantilla de la serie y ya incluye su código: no concatenes series y number.
  4. Si tienes VeriFactu activo, genera el registro de alta y el QR. Si ese paso no valida, no emite. El envío a la AEAT se hace después, en segundo plano.
  5. Si tienes el SII activo, deja la factura pendiente de envío.

El estado de los envíos fiscales se consulta en Cumplimiento.

:::info Aún no disponible TicketBAI todavía no está disponible, así que la emisión no firma ni envía facturas a las haciendas forales. :::

Respuesta 200, resumida:

{
  "id": "00000000-0000-0000-0000-000000000001",
  "direction": "issued",
  "status": "issued",
  "series": "A",
  "number": "A-1",
  "issue_date": "2026-11-02",
  "external_id": "PEDIDO-2026-001",
  "supplier_tax_id": "B10000008",
  "customer_tax_id": "B10000016",
  "currency": "EUR",
  "total_base": 1000.0,
  "total_tax": 210.0,
  "total": 1210.0
}

La API no emite en bloque: emite cada borrador con su llamada.

Emitir con el número de tu programa

Si tu programa ya numera las facturas, envía su número en invoice_number:

curl -X POST "https://app.faxtal.com/api/v1.1/issued-invoices/00000000-0000-0000-0000-000000000001/issue" \
  -H "X-API-Key: fctXXXXXXXX_YYYYYYYYYYYYYYYY" \
  -H "Content-Type: application/json" \
  -d '{"invoice_number": "A-0042"}'
  • Envía el número completo, con la serie, tal como figura en la factura.
  • Tiene que encajar con la plantilla de la serie del borrador: con el código, el prefijo y los ceros a la izquierda que usa esa serie. Si no encaja, 422 con forced_number_invalid.
  • No puede tenerlo otra factura, de esa serie o de otra. Si lo tiene, 409 con forced_number_in_use.
  • El borrador se valida antes de usar el número. Si tiene errores, el número no se usa y puedes volver a enviarlo cuando los corrijas.
  • Si el número va por delante del contador de la serie, el contador avanza hasta él: la siguiente emisión sin invoice_number continúa desde ahí.

:::warning La API no comprueba que la numeración sea correlativa. La numeración de una serie tiene que serlo (artículo 6.1.a del Reglamento de facturación, Real Decreto 1619/2012), y con invoice_number esa responsabilidad es tuya: no dejes huecos ni emitas números fuera de orden. :::

Errores

HTTPcodeCausa
404invoice_not_foundLa factura no existe o no es una emitida de tu empresa.
409invalid_status_transitionLa factura no es un borrador. El detalle trae from y to.
409invoice_queued_for_bulk_issueLa factura está reservada por una emisión en bloque.
409bulk_issue_series_activeHay una emisión en bloque en curso en esa serie.
409company_not_verifiedLa empresa no está verificada.
409forced_number_in_useEl invoice_number ya lo tiene otra factura, de esa serie o de otra.
409invoice_number_already_assignedUn intento de emisión anterior ya asignó otro número al borrador. El detalle trae number.
422validation_failedEl borrador no pasa la validación o la de VeriFactu. El detalle trae errors.
422missing_emission_fieldsFalta la serie. El detalle trae missing.
422forced_number_invalidEl invoice_number no encaja con la plantilla de la serie.
422request_validation_errorEl cuerpo no es válido: invoice_number vacío, de más de 60 caracteres o con campos que no existen.

Importar facturas emitidas en otro programa

POST /api/v1.1/issued-invoices/import

:::warning Una factura importada queda marcada como emitida fuera de la plataforma. No pasa por la emisión: no genera registro VeriFactu y no queda pendiente de envío al SII. Úsala para migrar históricos. Para facturar, crea un borrador y emítelo. :::

Qué enviar, además del formato canónico:

  • header.invoice_series_code, header.invoice_number e issue_data.issue_date. Son obligatorios, y la fecha no puede ser futura.
  • header.invoice_number tal como figura en la factura.
  • supplier.tax_id: obligatorio, y tiene que ser el NIF de tu empresa.
  • meta.external_ref es opcional. Si falta, se usa el número de factura.
  • No envíes los campos que deduce el sistema (ver Borradores).
{
  "schema_version": "json_1_1",
  "meta": {
    "direction": "issued",
    "source_system": "programa-anterior"
  },
  "invoice": {
    "supplier": {
      "person_type_code": "J",
      "tax_id": "B10000008",
      "name": "Empresa Demo S.L."
    },
    "customer": {
      "person_type_code": "J",
      "tax_id": "B10000016",
      "name": "Cliente Prueba S.L."
    },
    "header": {
      "invoice_series_code": "F",
      "invoice_number": "F-2025-0042",
      "invoice_type_code": "01"
    },
    "issue_data": {
      "issue_date": "2025-12-15",
      "tax_currency_code": "EUR"
    },
    "totals": {
      "total_gross_amount_before_taxes": 500.0,
      "total_tax_outputs": 105.0,
      "invoice_total": 605.0
    },
    "lines": [
      {
        "item_description": "Mantenimiento diciembre",
        "quantity": 1,
        "unit_price_without_tax": 500.0,
        "tax_treatment_code": "TAXABLE_NON_EXEMPT",
        "tax_output_rate": 21.0
      }
    ]
  }
}
curl -X POST "https://app.faxtal.com/api/v1.1/issued-invoices/import" \
  -H "X-API-Key: fctXXXXXXXX_YYYYYYYYYYYYYYYY" \
  -H "Content-Type: application/json" \
  -d @importada.json

Respuesta 201:

{
  "success": true,
  "id": "00000000-0000-0000-0000-000000000002",
  "errors": []
}

Cómo funciona:

  • La factura queda en estado issued y su histórico muestra el evento imported.
  • La validación no bloquea: la factura se guarda aunque tenga errores, que recibes en errors. success es true también en ese caso, así que revisa siempre errors.
  • Si ya existe una factura con el mismo número (el número incluye la serie): si es otra importada, se actualiza (una ya enviada sigue como sent); si la emitió la plataforma, la importada está anulada o es de otra serie, responde 409 invoice_update_not_allowed.
  • Una importada que ya consta en un modelo presentado no admite cambios en sus datos fiscales.

Errores

HTTPcodeCausa
422missing_required_fieldsFalta la serie, el número o la fecha. El detalle trae missing.
422future_issue_dateLa fecha de expedición es futura.
422issuer_tax_id_requiredFalta supplier.tax_id.
422issuer_tax_id_mismatchsupplier.tax_id no es el NIF de tu empresa.
422inferred_fields_not_allowedHas enviado campos que deduce el sistema.
409invoice_update_not_allowedEse número ya lo tiene una factura emitida por la plataforma, o una importada anulada.
409issued_invoice_fiscally_lockedLa importada ya consta en un modelo presentado. El detalle trae reasons y locked_fields_changed.

Importar en bloque

POST /api/v1.1/issued-invoices/import/batch

El cuerpo es el mismo que el de los borradores en bloque: un objeto con invoices, y cada elemento con su invoice completa (serie, número y fecha incluidos).

curl -X POST "https://app.faxtal.com/api/v1.1/issued-invoices/import/batch" \
  -H "X-API-Key: fctXXXXXXXX_YYYYYYYYYYYYYYYY" \
  -H "Content-Type: application/json" \
  -d @lote-historico.json
  • La llamada espera a que termine todo el lote.
  • Cada factura va por separado: si una se rechaza, las demás se importan igual. Las de una misma serie se procesan en orden.
  • La respuesta tiene la misma forma que en borradores (batch_id, status, total, accepted, rejected, items), y items[].number trae el número importado.
  • La respuesta detalla como máximo 500 facturas. Envía lotes de 500 o menos.

Anular una factura

POST /api/v1.1/issued-invoices/{invoice_id}/cancel

Sin cuerpo.

curl -X POST "https://app.faxtal.com/api/v1.1/issued-invoices/00000000-0000-0000-0000-000000000001/cancel" \
  -H "X-API-Key: fctXXXXXXXX_YYYYYYYYYYYYYYYY"
  • Admite facturas en issued o sent. En otro estado responde 409 invalid_status_transition.
  • La factura pasa a cancelled y la respuesta 200 la devuelve con la forma de la consulta.
  • Si era una rectificativa, la original deja de figurar como rectificada por ella.
  • Los cobros asociados a la factura se anulan.

:::warning La comunicación fiscal de la anulación tiene limitaciones conocidas:

  • Solo se intenta si la factura estaba en issued. Si estaba en sent, hoy no se comunica ninguna anulación.
  • El registro fiscal de la anulación no está garantizado: si falla, la factura queda anulada igualmente. Comprueba el resultado en Cumplimiento.
  • Con el SII activo, la anulación queda pendiente como modificación, no como baja.
  • No anules una factura importada: no tiene registro de alta. Si hay que retirarla, elimínala.
  • No repitas la llamada: si no sabes si se aplicó, consulta antes el estado de la factura. :::

Para corregir una factura emitida, emite una rectificativa.


Emitir una rectificativa

No hay una operación propia: una rectificativa es un borrador con tipo rectificativo que emites como cualquier otro.

  1. Crea el borrador con PUT /api/v1.1/drafts. Usa header.invoice_type_code 03 (rectificativa) o 04 (rectificativa simplificada) y añade el bloque header.corrective.
  2. Emítelo con POST /api/v1.1/issued-invoices/{invoice_id}/issue.
Campo de header.correctiveObligatorioDescripción
invoice_numberSíNúmero de la factura rectificada. Ya incluye la serie.
invoice_issue_dateSíFecha de expedición de la factura rectificada (YYYY-MM-DD).
reason_codeSíMotivo de la rectificación: código de dos dígitos del catálogo (01 a 25).
correction_typeSíS (por sustitución) o D (por diferencias).
corrected_taxable_base, corrected_tax_amountCon SBase y cuota rectificadas de la factura original.
reason_descriptionNoTexto del motivo.
tax_period.start_date, tax_period.end_dateNoPeriodo de la factura rectificada.
"header": {
  "invoice_series_code": "R",
  "invoice_type_code": "03",
  "corrective": {
    "invoice_number": "A-1",
    "invoice_issue_date": "2026-11-02",
    "reason_code": "01",
    "correction_type": "D"
  }
}

Si falta un dato, el borrador se guarda con errores y no se puede emitir. Los códigos son corrective_reason_required, corrective_reason_unknown, corrective_invoice_number_required, corrective_invoice_issue_date_required, corrective_correction_type_required y corrective_substitution_amounts_required.

Al consultar una factura, corrections muestra la relación:

  • corrects: la factura a la que rectifica (correction_type, reason_code, corrected_series, corrected_number, corrected_issue_date, match_status). corrected_invoice_id es null si la original no está en la plataforma.
  • corrected_by: las rectificativas que la corrigen (invoice_id, series, number, issue_date, correction_type).

Consultar y listar

Una factura

GET /api/v1.1/issued-invoices/{invoice_id}

curl "https://app.faxtal.com/api/v1.1/issued-invoices/00000000-0000-0000-0000-000000000001" \
  -H "X-API-Key: fctXXXXXXXX_YYYYYYYYYYYYYYYY"
CampoDescripción
idIdentificador de la factura.
directionissued.
statusEstado (ver la tabla del principio).
series, numberSerie y número. El número ya incluye la serie.
issue_dateFecha de expedición.
external_idTu meta.external_ref.
supplier_tax_id, supplier_nameEmisor.
customer_tax_id, customer_nameCliente.
currencyDivisa.
total_base, total_tax, totalBase imponible, cuota y total.
created_at, updated_atFechas de alta y de última modificación.
correctionsRelación con rectificativas, o null.
fiscalEstado fiscal: qr_url, legend y status. Solo en esta ficha y solo si la factura está emitida, enviada o anulada; en los listados va a null.

fiscal es lo que necesitas para imprimir la factura por tu cuenta: el QR y la leyenda que exige VeriFactu (o TicketBAI, si la empresa opera en territorio foral). status refleja el registro fiscal (verifactu_accepted, verifactu_pending, not_registered…).

El canónico

GET /api/v1.1/issued-invoices/{invoice_id}/canonical

Devuelve el JSON canónico tal y como lo guardó Faxtal: normalizado y con los campos que el sistema infiere (clasificación fiscal, taxable, exempt, is_simplified…). Es lo que se declara a Hacienda, y lleva las líneas y los impuestos que la ficha resumida no trae.

curl "https://app.faxtal.com/api/v1.1/issued-invoices/00000000-0000-0000-0000-000000000001/canonical" \
  -H "X-API-Key: fctXXXXXXXX_YYYYYYYYYYYYYYYY"

:::warning No se reenvía tal cual La respuesta no vale como cuerpo de PUT /api/v1.1/drafts: ese endpoint rechaza los campos inferidos con 422 inferred_fields_not_allowed. Úsalo para leer y para conciliar, no para reeditar. :::

Si la factura no tiene canónico guardado, responde 409 canonical_not_available.

La lista

GET /api/v1.1/issued-invoices

ParámetroDescripción
statusdraft, issued, sent, cancelled o queued. Sin él, incluye también los borradores.
seriesCódigo de serie.
customer_tax_idNIF del cliente.
numberNúmero de factura exacto. Sirve para recuperar una factura cuyo id has perdido.
external_refTu referencia (meta.external_ref), exacta.
issue_date_from, issue_date_toRango de fecha de expedición (YYYY-MM-DD).
limitDe 1 a 500. Por defecto, 50.
offsetDesplazamiento. Por defecto, 0.
curl -G "https://app.faxtal.com/api/v1.1/issued-invoices" \
  -H "X-API-Key: fctXXXXXXXX_YYYYYYYYYYYYYYYY" \
  -d status=issued -d issue_date_from=2026-11-01 -d issue_date_to=2026-11-30

Respuesta 200: items, total, limit y offset. Los resultados salen ordenados por serie y, dentro de cada serie, de la fecha más reciente a la más antigua. Un status desconocido responde 400 unknown_status.

Validar un JSON sin guardarlo

POST /api/v1.1/issued-invoices/validate funciona igual que la validación de borradores.


Eliminar una factura importada

DELETE /api/v1.1/issued-invoices/{invoice_id}

curl -X DELETE "https://app.faxtal.com/api/v1.1/issued-invoices/00000000-0000-0000-0000-000000000002" \
  -H "X-API-Key: fctXXXXXXXX_YYYYYYYYYYYYYYYY"

Respuesta 204, sin cuerpo. Solo se pueden eliminar facturas importadas. Con cualquier otra, responde 409 invoice_delete_not_allowed. También responde 409 si la importada ya consta en un modelo presentado, y entonces el detalle trae reasons.


Ver el histórico

GET /api/v1.1/issued-invoices/{invoice_id}/events

curl "https://app.faxtal.com/api/v1.1/issued-invoices/00000000-0000-0000-0000-000000000001/events" \
  -H "X-API-Key: fctXXXXXXXX_YYYYYYYYYYYYYYYY"

Respuesta 200, resumida:

[
  {
    "event_type": "state_transition",
    "event_code": "issued",
    "occurred_at": "2026-11-02T09:20:00",
    "actor": { "user_id": null, "api_key_id": 42 },
    "from_status": "VALIDATED",
    "to_status": "ISSUED",
    "details": { "issue_date": "2026-11-02" }
  }
]

Algunos event_code: issued (o imported en una importada), sent, cancelled, document_added y document_deleted. from_status y to_status usan los nombres de estado internos, en mayúsculas.


Documentos adjuntos

OperaciónRutaScope
ListarGET /api/v1.1/issued-invoices/{invoice_id}/documentsinvoices:read
AñadirPOST /api/v1.1/issued-invoices/{invoice_id}/documentsinvoices:write
DescargarGET /api/v1.1/issued-invoices/{invoice_id}/documents/{doc_id}invoices:read
EliminarDELETE /api/v1.1/issued-invoices/{invoice_id}/documents/{doc_id}invoices:write

Para añadir, envía el fichero como multipart/form-data en el campo file:

curl -X POST "https://app.faxtal.com/api/v1.1/issued-invoices/00000000-0000-0000-0000-000000000001/documents" \
  -H "X-API-Key: fctXXXXXXXX_YYYYYYYYYYYYYYYY" \
  -F "file=@albaran.pdf;type=application/pdf"

Respuesta 201:

{
  "public_id": "00000000-0000-0000-0000-0000000000d1",
  "doc_type": "pdf_render",
  "file_name": "albaran.pdf",
  "content_type": "application/pdf",
  "metadata": null,
  "created_at": "2026-11-02T09:30:00"
}
  • public_id es el doc_id para descargar o eliminar.
  • doc_type sale del tipo de contenido: pdf_render para un PDF, xml_facturae para un XML y attachment para el resto.
  • El fichero puede ocupar hasta 16 MB (413 file_too_large) y no puede estar vacío (422 empty_file).
  • Descargar devuelve el fichero con su nombre. Un doc_id que no existe responde 404 document_not_found.
  • Eliminar responde 204.

Descargar el PDF

GET /api/v1.1/issued-invoices/{invoice_id}/pdf

curl "https://app.faxtal.com/api/v1.1/issued-invoices/00000000-0000-0000-0000-000000000001/pdf" \
  -H "X-API-Key: fctXXXXXXXX_YYYYYYYYYYYYYYYY" \
  -o factura.pdf

Devuelve application/pdf. Si la factura tiene registro VeriFactu, el PDF lleva su QR.

El parámetro template elige una plantilla general como <diseño>-<estilo> (por ejemplo, clasica-corporativo; la lista está en Formatos). Sin él, o con otro valor, se usa la plantilla de la serie de la factura o, si no tiene, la de la empresa.


Exportar y enviar por email

  • Exportar a FacturaE, UBL o CII: GET /api/v1.1/issued-invoices/{invoice_id}/export?format=.... Solo facturas en issued o sent. Las facturas con retención de IRPF no se exportan a UBL ni a CII: usa FacturaE. Ver Formatos.
  • Enviar por email: POST /api/v1.1/issued-invoices/{invoice_id}/send. Ver Envío por email.

Ver también

On this page