Usa la API de Facturovia para integrar la facturación en tus aplicaciones, web shops o automatizaciones.
Todas las peticiones requieren una cabecera Authorization con tu clave de API:
curl -H "Authorization: Bearer fv_live_YOUR_KEY" \
https://facturo-production-c176.up.railway.app/api/invoices Genera una clave en Configuración →Todas las rutas devuelven JSON. Los IDs son UUID. La fecha del cuerpo se acepta en formato YYYY-MM-DD.
| Método | Ruta | Descripción |
|---|---|---|
| GET | /invoices | List invoices. Supports ?external_reference=ORDER-2847 for exact match. |
| POST | /invoices | Create a draft invoice. Accepts external_reference (optional, ≤ 255 chars). |
| GET | /invoices/:id | Get a single invoice with line items |
| POST | /invoices/:id/issue | Issue a draft invoice (status → issued) |
| POST | /invoices/:id/correct | Rectificative invoice that negates every original line |
| POST | /invoices/:id/rectify | Partial rectificative — only the items you specify (positive qty, server negates) |
| GET | /invoices/:id/pdf | Download PDF of an issued invoice |
| GET | /clients | List clients |
| POST | /clients | Create a client |
| POST | /clients/find-or-create | Find existing client by tax_id or create new one (idempotent) |
| GET | /quotes | List quotes. Supports ?external_reference= filter. |
| POST | /quotes | Create a quote. Accepts external_reference (optional). |
Busca un cliente por NIF/CIF. Si no existe, lo crea automáticamente. Patrón típico para integraciones con tiendas online: el cliente del e-commerce llega con su NIF, este endpoint te devuelve un client_id usable para crear la factura.
// 1. Find or create a client by tax_id (idempotent)
const clientRes = await fetch('https://facturo-production-c176.up.railway.app/api/clients/find-or-create', {
method: 'POST',
headers: { 'Authorization': 'Bearer fv_live_...', 'Content-Type': 'application/json' },
body: JSON.stringify({
tax_id: 'B12345674',
name: 'Talleres García S.L.',
email: 'info@talleresgarcia.es',
address: 'Calle Mayor 1',
city: 'Madrid', postal_code: '28001', country: 'ES',
}),
});
const { client, created } = await clientRes.json();
// created === true if new, false if it already existed
// 2. Create the invoice using the returned client.id
const invoiceRes = await fetch('https://facturo-production-c176.up.railway.app/api/invoices', {
method: 'POST',
headers: { 'Authorization': 'Bearer fv_live_...', 'Content-Type': 'application/json' },
body: JSON.stringify({
client_id: client.id,
invoice_date: new Date().toISOString().split('T')[0],
currency: 'EUR', exchange_rate: 1,
items: [{
description: 'Filtro de aceite Toyota Corolla',
quantity: 2, unit_price: 15.99,
vat_rate: 21, discount_percent: 0,
}],
}),
});
const invoice = await invoiceRes.json();
// 3. Issue the invoice and download the PDF
await fetch(`https://facturo-production-c176.up.railway.app/api/invoices/${invoice.id}/issue`, {
method: 'POST',
headers: { 'Authorization': 'Bearer fv_live_...' },
});
const pdfRes = await fetch(`https://facturo-production-c176.up.railway.app/api/invoices/${invoice.id}/pdf`, {
headers: { 'Authorization': 'Bearer fv_live_...' },
});
const pdfBlob = await pdfRes.blob();Las facturas y presupuestos aceptan un campo opcional external_reference (≤ 255 caracteres) para guardar el ID de pedido de tu sistema. Después puedes filtrar por él (?external_reference=ORDER-2847) para encontrar la factura original sin tener que mantener una tabla de equivalencias en tu lado.
// E-commerce return / rectification workflow using external_reference
// 1. Storefront creates the original invoice with its order id
await fetch('https://facturo-production-c176.up.railway.app/api/invoices', {
method: 'POST',
headers: { 'Authorization': 'Bearer fv_live_...', 'Content-Type': 'application/json' },
body: JSON.stringify({
external_reference: 'ORDER-2847',
client_id: client.id,
invoice_date: new Date().toISOString().split('T')[0],
currency: 'EUR', exchange_rate: 1,
items: [
{ description: 'Filtro aceite REF-001', quantity: 1, unit_price: 15.99, vat_rate: 21, discount_percent: 0 },
{ description: 'Correa distribución REF-045', quantity: 2, unit_price: 89.50, vat_rate: 21, discount_percent: 0 },
],
}),
});
// 2. When the customer initiates a return, look up the original by your
// own order id — no need to store the Facturovia invoice id locally.
const r = await fetch('https://facturo-production-c176.up.railway.app/api/invoices?external_reference=ORDER-2847', {
headers: { 'Authorization': 'Bearer fv_live_...' },
});
const { data: [original] } = await r.json();
// 3. Issue a partial rectificativa for ONLY the returned items.
// Quantities are positive — the server negates them. Items must
// match a line on the original (by reference if provided, else by
// description) and quantity is capped to the original quantity.
await fetch(`https://facturo-production-c176.up.railway.app/api/invoices/${original.id}/rectify`, {
method: 'POST',
headers: { 'Authorization': 'Bearer fv_live_...', 'Content-Type': 'application/json' },
body: JSON.stringify({
items: [
{ description: 'Filtro aceite REF-001', reference: 'REF-001', quantity: 1, unit_price: 15.99, vat_rate: 21, discount_percent: 0 },
{ description: 'Correa distribución REF-045', reference: 'REF-045', quantity: 2, unit_price: 89.50, vat_rate: 21, discount_percent: 0 },
],
notes: 'Devolución parcial — piezas defectuosas',
causa_rectificacion: 'R1',
}),
});
// → 201 with { invoice: { id, status: "draft", is_corrective: true,
// original_invoice_id, total: <negative>, ... } }Cada clave puede tener uno de los siguientes niveles de acceso:
La API devuelve códigos HTTP estándar:
401 — Clave inválida o ausente.402 — Plan agotado o no permitido. Considera actualizar a Profesional.403 — La clave es de solo lectura o el rol no tiene permiso.422 — Datos inválidos. La respuesta incluye los campos con error.