Facturas recibidas
Las facturas recibidas son las que te emiten tus proveedores. Puedes registrarlas con el formato canónico, importarlas desde un XML o pedir una propuesta a partir de un PDF o una imagen.
Todas las llamadas usan la URL base https://app.faxtal.com/api/v1.1 y la cabecera X-API-Key (ver Autenticación).
| Operación | Scope de la API key |
|---|---|
| Consultar, listar, validar, ver eventos, descargar documentos y PDF | invoices:read |
| Registrar, importar, reconocer, eliminar, y añadir o eliminar documentos | received:write |
Sin el scope necesario, la API responde 403 con el código scope_missing.
Estados
status | Significado |
|---|---|
received | Registrada y válida. |
draft | Pendiente de revisar, por ejemplo porque se registró con errores de validación. |
Registrar o actualizar con JSON canónico
PUT /api/v1.1/received-invoices
Qué enviar, en el formato canónico:
meta.source_system.meta.directionse fija siempre areceived.invoice.supplier: el proveedor.invoice.customer: tu empresa.header.invoice_number: el número completo, tal como lo pone el proveedor.invoice_series_codees opcional.header.invoice_type_code.issue_data.issue_date: la fecha de expedición. No puede ser futura.issue_data.receipt_date: la fecha en que registras la factura. Si falta, se usa la de hoy.- No envíes los campos que deduce el sistema (ver Borradores). Si llegan, responde
422inferred_fields_not_allowed.
Una factura usa un solo grupo de impuesto, el de issue_data.tax_group_code. Si está en otra divisa, se convierte a euros. Si no se puede determinar el tipo de cambio, la petición se rechaza con 422.
:::info Aún no disponible
El grupo IGIC (Canarias) todavía no está disponible. Hoy el grupo es siempre IVA.
:::
recibida.json:
{
"schema_version": "json_1_1",
"meta": {
"direction": "received",
"source_system": "mi-erp"
},
"invoice": {
"supplier": {
"person_type_code": "J",
"tax_id": "B10000024",
"name": "Proveedor Ejemplo S.L."
},
"customer": {
"person_type_code": "J",
"tax_id": "B10000008",
"name": "Empresa Demo S.L."
},
"header": {
"invoice_number": "FV-2026-0315",
"invoice_type_code": "01"
},
"issue_data": {
"issue_date": "2026-10-28",
"receipt_date": "2026-11-02",
"tax_currency_code": "EUR"
},
"totals": {
"total_gross_amount_before_taxes": 250.0,
"total_tax_outputs": 52.5,
"invoice_total": 302.5
},
"lines": [
{
"item_description": "Material de oficina",
"quantity": 1,
"unit_price_without_tax": 250.0,
"tax_treatment_code": "TAXABLE_NON_EXEMPT",
"tax_output_rate": 21.0
}
]
}
}
curl -X PUT "https://app.faxtal.com/api/v1.1/received-invoices" \
-H "X-API-Key: fctXXXXXXXX_YYYYYYYYYYYYYYYY" \
-H "Content-Type: application/json" \
-d @recibida.json
Respuesta 201, también cuando actualiza:
{
"success": true,
"id": "00000000-0000-0000-0000-000000000003",
"errors": []
}
La validación no bloquea: la factura se registra aunque tenga errores. En ese caso success es false, los errores vienen en errors y la factura queda en draft.
Duplicados y actualizaciones
- Una recibida se identifica por el NIF del proveedor, el número y el año de la fecha de expedición. La serie no cuenta.
- Si envías otra factura con esa misma clave, se actualiza la existente en lugar de crear un duplicado. La API no responde
409por duplicado. - Con
?invoice_id=<id>actualizas esa factura concreta. Si el id es de una factura emitida, responde409invoice_update_not_allowed. - Si la factura ya consta en un modelo presentado, no admite cambios en sus datos fiscales. Si solo fue aceptada en el SII, el cambio se admite y queda pendiente de reenviarse al SII.
Errores
| HTTP | code | Causa |
|---|---|---|
422 | missing_required_fields | Falta header.invoice_number o issue_data.issue_date. El detalle trae missing. |
422 | future_issue_date | La fecha de expedición es futura. |
422 | inferred_fields_not_allowed | Has enviado campos que deduce el sistema. |
409 | invoice_update_not_allowed | El invoice_id es de una factura emitida. |
409 | received_invoice_fiscally_locked | La factura ya consta en un modelo presentado. El detalle trae reasons y locked_fields_changed. |
409 | invoice_race_condition | Otra petición ha escrito la misma factura a la vez. Reintenta. |
Importar un XML (Facturae, UBL o CII)
POST /api/v1.1/received-invoices/import?format=<formato>
format | Formato |
|---|---|
facturae_3_2_2 | Facturae 3.2.2 |
facturae_3_2_1 | Facturae 3.2.1 |
facturae_3_2 | Facturae 3.2 |
ubl_2_1 | UBL 2.1 |
cii_d16b | CII D16B |
- El cuerpo es el XML tal cual, no un formulario.
- La cabecera
Content-Typetiene que serapplication/xmlotext/xml. - El XML puede ocupar hasta 10 MB.
- La validación es estricta: si el XML tiene errores, no se registra nada.
- Se registra igual que con JSON canónico: queda en
receivedy, si ya existe una recibida del mismo proveedor con ese número en el mismo año, la actualiza. - El comprador del XML tiene que ser tu empresa (salvo en facturas simplificadas).
- Si el XML no trae fecha de recepción, no se usa la de hoy: la factura se imputa por su fecha de expedición. Al volver a importarla se conserva la fecha de recepción que ya tuviera.
curl -X POST "https://app.faxtal.com/api/v1.1/received-invoices/import?format=facturae_3_2_2" \
-H "X-API-Key: fctXXXXXXXX_YYYYYYYYYYYYYYYY" \
-H "Content-Type: application/xml" \
--data-binary @factura-proveedor.xml
Respuesta 201:
{
"success": true,
"id": "00000000-0000-0000-0000-000000000004",
"errors": []
}
Errores
| HTTP | code | Causa |
|---|---|---|
400 | empty_body | El cuerpo está vacío. |
413 | payload_too_large | El XML supera 10 MB. El detalle trae max_bytes. |
415 | unsupported_media_type | El Content-Type no es XML. El detalle trae expected. |
422 | unsupported_invoice_source_transform | El formato indicado no se puede convertir. |
422 | — | El XML no se puede leer o no pasa la validación. El detalle describe los errores. |
422 | missing_required_fields | El XML no trae número o fecha de expedición. El detalle trae missing. |
422 | future_issue_date | La fecha de expedición es futura. |
422 | recipient_tax_id_mismatch | El NIF del comprador no es el de tu empresa. |
422 | recipient_tax_id_required | El XML no trae el NIF del comprador. |
409 | received_invoice_fiscally_locked | La factura ya consta en un modelo presentado. El detalle trae reasons y locked_fields_changed. |
409 | invoice_race_condition | Otra petición ha escrito la misma factura a la vez. Reintenta. |
Reconocer un PDF o una imagen
POST /api/v1.1/received-invoices/recognize
Lee el documento y devuelve una propuesta de factura en formato canónico. No registra nada: la revisas y la registras tú.
- Envía el fichero como
multipart/form-dataen el campofile. - Admite PDF, JPEG, PNG y TIFF, de hasta 10 MB. Un PDF puede tener hasta 8 páginas.
- La llamada espera al resultado.
- Cada documento cuenta para el límite mensual de reconocimientos de tu plan.
- Un mismo fichero solo se reconoce una vez. Si lo vuelves a enviar, se rechaza.
curl -X POST "https://app.faxtal.com/api/v1.1/received-invoices/recognize" \
-H "X-API-Key: fctXXXXXXXX_YYYYYYYYYYYYYYYY" \
-F "file=@factura-proveedor.pdf;type=application/pdf"
Respuesta 200, resumida:
{
"job_id": "00000000-0000-0000-0000-0000000000a1",
"status": "recognized_pending_review",
"canonical_draft": {
"schema_version": "json_1_1",
"meta": {
"direction": "received",
"recognition_status": "recognized_pending_review",
"recognition_score": 0.82
},
"invoice": { "...": "proveedor, cabecera, fechas, líneas y totales" },
"recognition": {
"requires_human_review": true,
"review_reasons": ["..."],
"field_scores": { "...": 0.9 }
}
}
}
status | Significado |
|---|---|
recognized_ready | Confianza alta. Revisa igualmente antes de registrar. |
recognized_pending_review | Hay datos dudosos: revísalos. |
recognized_rejected | No parece una factura o la confianza es demasiado baja. canonical_draft puede venir vacío. |
La confianza global está en canonical_draft.meta.recognition_score, de 0 a 1. El detalle por campo y los motivos de revisión están en canonical_draft.recognition.
Registrar la propuesta
La API no tiene un paso de confirmación: reconoces el documento y después registras la factura con PUT /api/v1.1/received-invoices. La propuesta no se puede enviar tal cual: trae campos que el alta rechaza con 422 inferred_fields_not_allowed. Antes de enviarla:
- Revisa y corrige los datos: proveedor, número, fechas e importes.
- Quita
header.is_simplifiedyheader.is_corrective, que vienen siempre. - Quita, si aparecen,
taxable,exempt,tax_category_code,tax_output_codeytax_withheld_codede las líneas;taxable,exempt,tax_category_codeytax_type_codedetaxes_outputs[]ytaxes_withheld[]; ysubdivision_typede las direcciones. - Envía el resultado con
PUT /api/v1.1/received-invoices.
Errores
| HTTP | code | Causa |
|---|---|---|
402 | quota_exceeded | Has llegado al límite mensual de reconocimientos de tu plan. |
422 | recognition_file_invalid | El fichero está vacío o supera el tamaño máximo. |
503 | recognition_disabled | El reconocimiento no está disponible. |
Validar
POST /api/v1.1/received-invoices/validate: valida un JSON canónico sin guardarlo. Respondeis_valid,errorsydata, igual que la validación de borradores.POST /api/v1.1/received-invoices/{invoice_id}/validate: vuelve a validar una recibida registrada. Respondeid,is_valid,statusyerrors.
curl -X POST "https://app.faxtal.com/api/v1.1/received-invoices/validate" \
-H "X-API-Key: fctXXXXXXXX_YYYYYYYYYYYYYYYY" \
-H "Content-Type: application/json" \
-d @recibida.json
Consultar y listar
Una factura
GET /api/v1.1/received-invoices/{invoice_id}
curl "https://app.faxtal.com/api/v1.1/received-invoices/00000000-0000-0000-0000-000000000003" \
-H "X-API-Key: fctXXXXXXXX_YYYYYYYYYYYYYYYY"
Devuelve la factura con los mismos campos que una emitida (id, direction, status, number, issue_date, supplier_tax_id, supplier_name, totales y corrections), con direction a received.
El canónico
GET /api/v1.1/received-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/received-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/received-invoices
| Parámetro | Descripción |
|---|---|
status | received, draft, issued, sent o cancelled. |
supplier_tax_id | NIF del proveedor. |
series | Código de serie, si la factura lo trae. |
number | Número de factura exacto. Sirve para recuperar una factura cuyo id has perdido. |
external_ref | Tu referencia (meta.external_ref), exacta. |
issue_date_from, issue_date_to | Rango de fecha de expedición (YYYY-MM-DD). |
limit | De 1 a 500. Por defecto, 50. |
offset | Desplazamiento. Por defecto, 0. |
curl -G "https://app.faxtal.com/api/v1.1/received-invoices" \
-H "X-API-Key: fctXXXXXXXX_YYYYYYYYYYYYYYYY" \
-d supplier_tax_id=B10000024
Respuesta 200: items, total, limit y offset.
Eliminar
DELETE /api/v1.1/received-invoices/{invoice_id}
curl -X DELETE "https://app.faxtal.com/api/v1.1/received-invoices/00000000-0000-0000-0000-000000000003" \
-H "X-API-Key: fctXXXXXXXX_YYYYYYYYYYYYYYYY"
Respuesta 204, sin cuerpo. Se borran también sus documentos adjuntos.
Si la factura ya consta en un modelo presentado o fue aceptada en el SII, responde 409 invoice_delete_not_allowed con los motivos en reasons.
Ver el histórico
GET /api/v1.1/received-invoices/{invoice_id}/events
Devuelve la lista de eventos con la misma forma que en las emitidas: event_type, event_code, occurred_at, actor, from_status, to_status y details.
Documentos adjuntos
| Operación | Ruta | Scope |
|---|---|---|
| Listar | GET /api/v1.1/received-invoices/{invoice_id}/documents | invoices:read |
| Añadir | POST /api/v1.1/received-invoices/{invoice_id}/documents | received:write |
| Descargar | GET /api/v1.1/received-invoices/{invoice_id}/documents/{doc_id} | invoices:read |
| Eliminar | DELETE /api/v1.1/received-invoices/{invoice_id}/documents/{doc_id} | received:write |
Es útil para guardar el original del proveedor junto a la factura registrada:
curl -X POST "https://app.faxtal.com/api/v1.1/received-invoices/00000000-0000-0000-0000-000000000003/documents" \
-H "X-API-Key: fctXXXXXXXX_YYYYYYYYYYYYYYYY" \
-F "file=@factura-proveedor.pdf;type=application/pdf"
Las reglas son las mismas que en las emitidas: campo file, hasta 16 MB, respuesta 201 con public_id (el doc_id) y doc_type.
Descargar el PDF
GET /api/v1.1/received-invoices/{invoice_id}/pdf
curl "https://app.faxtal.com/api/v1.1/received-invoices/00000000-0000-0000-0000-000000000003/pdf" \
-H "X-API-Key: fctXXXXXXXX_YYYYYYYYYYYYYYYY" \
-o recibida.pdf
Genera un PDF con los datos registrados; no es el documento original del proveedor. El parámetro template funciona igual que en las emitidas.
Ver también
- Formato canónico: todos los campos de
json_1_1. - Terceros y productos: tus proveedores.
- Importación: alta masiva por fichero.
- Cumplimiento: estado del SII.
- Errores: formato común de las respuestas de error.
- Referencia interactiva.