Faxtal

Conceptos

Lo que conviene entender antes de integrar: sobre qué empresa trabaja cada clave, cómo se identifican las facturas y cómo cambian de estado.

Empresa y API key

  • Cada API key pertenece a una sola empresa. Todo lo que haces con ella ocurre en esa empresa.
  • La empresa no va en la URL: la API la deduce de la clave. Consúltala con GET /api/v1.1/company.
  • GET /api/v1.1/companies devuelve una lista con un solo elemento, la empresa de la clave.
  • Una factura de otra empresa no existe para tu clave: la API responde 404 con invoice_not_found.
  • Para trabajar con varias empresas, usa una clave por empresa. Ver Multiempresa.
  • Para emitir, la empresa tiene que estar verificada en la aplicación. Si no lo está, emitir responde 409 con company_not_verified.

Identificadores

  • Cada factura tiene un id opaco, hoy un UUID. Es el {invoice_id} de las rutas.
  • external_id es tu referencia: el meta.external_ref que enviaste.
  • Guarda el id tal como lo devuelve la API. No lo construyas ni lo deduzcas del número.

Formato canónico json_1_1

Las facturas se envían en JSON con tres bloques: schema_version, meta e invoice.

{
  "schema_version": "json_1_1",
  "meta": {
    "direction": "issued",
    "source_system": "mi-erp",
    "external_ref": "PEDIDO-2026-001"
  },
  "invoice": {}
}
  • json_1_1 es el único valor admitido. Cualquier otro, json_1 incluido, se rechaza con unsupported_schema_version.
  • No envíes los campos que calcula el sistema, como tax_category_code o taxable en las líneas. La API responde 422 con inferred_fields_not_allowed y las rutas afectadas.
  • Las lecturas no devuelven el canónico, sino un resumen de la factura: id, status, series, number, partes y totales.

El contenido de invoice está en Formato canónico.

Dirección: emitidas y recibidas

directionQué esRecursos
issuedFacturas que expide tu empresa/drafts, /issued-invoices
receivedFacturas que tu empresa recibe de sus proveedores/received-invoices
  • En una emitida, el emisor (invoice.supplier) es tu empresa. En una recibida, el receptor (invoice.customer) es tu empresa. Si no coincide con la empresa de la clave, la API rechaza la factura.
  • /received-invoices guarda siempre la factura como recibida, diga lo que diga meta.direction.
  • Pedir una recibida por /issued-invoices/{invoice_id}, o al revés, responde 404 con invoice_not_found.

Estados y ciclo de vida

El campo status de la respuesta usa estos valores:

statusSignifica
draftBorrador de emitida. Aún no tiene número ni fecha de emisión.
queuedEn cola de una emisión en bloque lanzada desde la aplicación.
issuedEmitida: ya tiene número y fecha.
sentEmitida y enviada por email.
cancelledAnulada.
receivedRecibida registrada.

Qué operación cambia cada estado:

OperaciónDesdeHasta
PUT /api/v1.1/draftsNueva o draftdraft
POST /api/v1.1/issued-invoices/{invoice_id}/issuedraftissued
POST /api/v1.1/issued-invoices/{invoice_id}/sendissued o sentsent
POST /api/v1.1/issued-invoices/{invoice_id}/cancelissued o sentcancelled
POST /api/v1.1/issued-invoices/importNuevaissued
PUT /api/v1.1/received-invoicesNueva o receivedreceived
  • Borrador con errores. Un borrador se guarda aunque tenga errores de validación y sigue en draft. PUT /drafts responde success: false con la lista errors, y POST /drafts/{invoice_id}/validate devuelve is_valid.
  • Recibida con errores. Una recibida guardada con errores bloqueantes aparece con status: "draft" hasta que la corriges.
  • Estado que no admite la operación. La API responde 409 con invalid_status_transition. Sus campos from y to traen el estado interno en mayúsculas (ISSUED, CANCELLED).
  • En cola. Emitir una factura en queued responde 409 con invoice_queued_for_bulk_issue.
  • Listado de emitidas. GET /issued-invoices sin status incluye también borradores y facturas en cola. Filtra con status=issued si solo quieres las emitidas.
  • Borrado. Un borrador se puede borrar. Una emitida, solo si la importaste y no está incluida en un modelo presentado; si no, 409 con invoice_delete_not_allowed.

Qué se envía a Hacienda al emitir o anular está en Cumplimiento.

Series y numeración

  • En emitidas, invoice.header.invoice_series_code es obligatorio. Sin él, 422 con missing_required_fields.
  • Si la serie no existe, se crea al usarla. Una serie creada así numera con la forma {SERIE}-{SEQ}: la serie A da A-1, A-2, A-3… y el contador no se reinicia.
  • Las series que configuras en la aplicación pueden usar otra plantilla, con año, mes o ceros a la izquierda, pero siempre empiezan por el código de la serie.
  • El número se asigna al emitir: el siguiente de la serie o, si tu programa numera, el que envías en el cuerpo de la emisión (ver Facturas emitidas). En un borrador no envíes invoice_number ni issue_date: la API responde 422 con invoice_number_not_allowed o issue_date_not_allowed. La fecha de emisión es la del día en que emites.
  • El número ya incluye la serie. En la respuesta, series es "A" y number es "A-1". No los concatenes.
  • Al importar una emitida fuera de Faxtal (POST /issued-invoices/import) envías tú invoice_number e issue_date, tal como figuran en la factura. La fecha no puede ser futura: 422 con future_issue_date.
  • En recibidas, el número es el del proveedor y la serie es opcional.

Consultar las series: GET /api/v1.1/series devuelve las de tu empresa, con code (el valor que se envía en invoice_series_code), name, direction, prefix, template, is_default, is_corrective, is_active y current_seq. Filtros direction (issued o received) y active. Permiso de la clave: invoices:read.

current_seq es el último secuencial consumido: si numeras tú, te dice por dónde va la serie antes de emitir con tu número.

Paginación

Los listados se paginan con limit y offset:

curl -s "https://app.faxtal.com/api/v1.1/issued-invoices?status=issued&limit=100&offset=200" \
  -H "X-API-Key: $FAXTAL_API_KEY"

Respuesta 200 resumida:

{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000001",
      "direction": "issued",
      "status": "issued",
      "series": "A",
      "number": "A-201",
      "issue_date": "2026-09-14",
      "external_id": "PEDIDO-2026-201",
      "supplier_tax_id": "B10000008",
      "supplier_name": "Empresa Demo S.L.",
      "customer_tax_id": "B10000016",
      "customer_name": "Cliente Prueba S.L.",
      "currency": "EUR",
      "total_base": 1000.0,
      "total_tax": 210.0,
      "total": 1210.0,
      "created_at": "2026-09-14T10:15:00",
      "updated_at": "2026-09-14T10:15:02",
      "corrections": null
    }
  ],
  "total": 1250,
  "limit": 100,
  "offset": 200
}
  • Para recorrer un listado entero, suma limit a offset hasta que offset alcance total.
  • limit vale 50 si no lo indicas. Su máximo depende del recurso:
ListadoMáximo de limit
/issued-invoices, /drafts, /received-invoices500
/third-parties, /products, /verifactu/submissions200
  • Un limit o un offset fuera de rango responde 422 con request_validation_error.
  • Algunos listados solo aceptan limit y devuelven items y total, sin offset: las incidencias de VeriFactu, y las facturas pendientes y los vencimientos del SII.
  • Las facturas salen ordenadas por serie y, dentro de cada serie, de la fecha de emisión más reciente a la más antigua. Si entran facturas mientras recorres un listado, una página puede repetir o saltarse alguna.

Filtros

ListadoFiltros
GET /issued-invoicesstatus, series, customer_tax_id, number, external_ref, issue_date_from, issue_date_to
GET /draftsseries, customer_tax_id, number, external_ref, issue_date_from, issue_date_to
GET /received-invoicesstatus, series, supplier_tax_id, number, external_ref, issue_date_from, issue_date_to
GET /third-partiessearch, role (customer o supplier)
GET /productssearch
  • series y los NIF buscan el valor exacto.
  • Las fechas van en formato YYYY-MM-DD y el rango incluye los dos extremos.
  • status admite draft, issued, sent, cancelled y queued. Un valor que no es un estado responde 400 con unknown_status.
  • number y external_ref también buscan el valor exacto.

Recuperar una factura cuyo id has perdido

external_ref es tu propia referencia: la envías en meta.external_ref al crear el borrador y vuelve en external_id. Si tu sistema pierde el id de Faxtal, búscala por ella y recupéralo:

curl -G "https://app.faxtal.com/api/v1.1/issued-invoices" \
  -H "X-API-Key: fctXXXXXXXX_YYYYYYYYYYYYYYYY" \
  -d external_ref=PEDIDO-2026-001

Si lo que conservas es el número, usa number (el número completo, con la serie: A-1).

Idempotencia

La API no admite la cabecera Idempotency-Key. Para reintentar sin duplicar, apóyate en estas claves:

OperaciónClaveSi repites la llamada
PUT /draftsmeta.external_ref, obligatorioActualiza el borrador con esa referencia en lugar de crear otro. Si esa factura ya está emitida, 409 con invoice_update_not_allowed.
POST /issued-invoices/{invoice_id}/issueEl invoice_idNo emite dos veces: la segunda llamada responde 409 con invalid_status_transition, también si envía invoice_number.
POST /issued-invoices/importSerie e invoice_numberActualiza la factura importada. Si ya está incluida en un modelo presentado, 409.
PUT /received-invoicesNIF del proveedor, número y año de la fecha de expediciónActualiza la recibida existente. Si sus datos fiscales ya no admiten cambios, 409 con received_invoice_fiscally_locked.
  • En PUT /drafts, sin meta.external_ref la API responde 422 con missing_required_fields. Para actualizar un borrador concreto, añade ?invoice_id= a la ruta.
  • Genera meta.external_ref desde tu sistema, por ejemplo con el identificador del pedido, y guárdalo junto al id que devuelve la API.
  • Tras un timeout, consulta el estado antes de repetir una emisión: GET /issued-invoices/{invoice_id}.
  • Los lotes (POST /drafts/batch, POST /issued-invoices/import/batch) devuelven accepted, rejected y el resultado de cada factura en items.

Ver también

On this page