Todo tu negocio en un solo plan: 5,90 €/mes. Ver precios →
Funcionalidades
Para tu oficio
Gestorías
Recursos
Precios
Empieza ahora Iniciar sesión

API y webhooks

Conecta ERPiA con tu web, tu tienda online, Zapier, Make, n8n o tu propio software. Una API REST para leer y escribir, y webhooks firmados para que te avisemos cuando pasa algo.

🔑

API REST

Facturas, presupuestos, contactos, artículos, gastos, cobros y proyectos. Lectura en todos los planes; escritura en el plan de pago.

📡

Webhooks firmados

Te avisamos en tu URL cuando se emite una factura, se registra un cobro o un cliente firma un presupuesto. Firma HMAC y reintentos automáticos.

📄

OpenAPI 3.1

La especificación completa, para importarla en Postman, Insomnia o generar un cliente: openapi.yaml.

Autenticación

Crea una clave en Mi ERPIA → API y webhooks. Se muestra una sola vez; guárdala. Al crearla eliges si es de solo lectura o de lectura y escritura. Va en la cabecera X-API-Key de cada petición.

URL base: https://erpia.es/api/v1

curl https://erpia.es/api/v1/me \
  -H "X-API-Key: erpia_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

Respuesta: los datos de tu cuenta, el plan y los permisos (scopes) de la clave.

Recursos

RecursoLeerEscribirFiltros
/facturasGET, GET /:idPOST, PATCH /:iddesde, hasta, estado, tipo, contacto_id, q, actualizado_desde
/presupuestosGET, GET /:idPOSTdesde, hasta, estado, contacto_id, q
/contactosGET, GET /:idPOST, PATCH /:idtipo, q
/articulosGET, GET /:idPOSTq, familia, activo
/gastosGET, GET /:idPOSTdesde, hasta, categoria, proyecto_id
/cobrosGETPOSTdesde, hasta, factura_id
/proyectosGET, GET /:idestado
/me, /eventosGET

Los listados devuelven data, count, limit y offset. Paginación con ?limit= (máximo 500) y ?offset=, con orden estable. Para sincronizar solo lo que ha cambiado, /facturas?actualizado_desde=2026-09-01T00:00:00Z.

Crear una factura

Las facturas creadas por API entran por el mismo camino que las de la pantalla: nacen como borrador con su número previsto y, al emitirlas, ERPiA asigna el correlativo definitivo de la serie y sella el registro Verifactu (huella encadenada y QR). No hay ninguna puerta trasera al encadenado: una factura emitida es inalterable y se corrige con una rectificativa.

POST /api/v1/facturas
X-API-Key: erpia_live_…
Idempotency-Key: pedido-8841
Content-Type: application/json

{
  "contacto_id": "0b0e3a4e-2f5d-4a2b-9f1e-1c2d3e4f5a6b",
  "lineas": [
    { "descripcion": "Reforma baño", "detalle": "Alicatado y fontanería", "cantidad": 1, "precio": 1450, "iva": 21 },
    { "descripcion": "Mano de obra", "cantidad": 8, "precio": 35, "unidad": "H" }
  ],
  "fecha_vencimiento": "2026-10-15",
  "emitir": true
}

Si indicas contacto_id, los datos del cliente se toman de su ficha; si no, envía al menos nombre_cliente. Cada línea puede llevar su propio iva (21, 10, 4 o 0). Con "emitir": true la factura sale numerada y sellada; sin él queda en borrador y puedes emitirla después con PATCH /facturas/:id {"emitir": true}. Un presupuesto (POST /presupuestos) devuelve además url_publica: el enlace donde tu cliente lo ve, lo acepta y lo firma desde el móvil.

Idempotencia

Envía la cabecera Idempotency-Key con un valor único por operación (el id de tu pedido, por ejemplo). Si la misma clave llega dos veces —porque un reintento de Zapier o un corte de red repitió la petición— ERPiA devuelve la misma respuesta con la cabecera Idempotent-Replayed: true y no crea nada dos veces. Las claves se recuerdan 7 días.

Webhooks salientes

Sin un disparador, una API de solo lectura no automatiza nada. En Mi ERPIA → API y webhooks añade la URL de tu servidor (o la que te da el «Webhook» de Zapier, Make o n8n), elige los eventos y ERPiA te avisará en segundos con un POST en JSON.

EventoCuándo
factura.emitidaUna factura, ticket o rectificativa sale del borrador (se numera y se sella)
factura.cobradaUna factura pasa a cobrada
presupuesto.creadoSe crea un presupuesto
presupuesto.aceptadoEl cliente acepta el presupuesto
presupuesto.firmadoEl cliente firma el presupuesto desde el enlace público
contacto.creadoSe da de alta un cliente o proveedor
gasto.creadoSe registra un gasto (a mano, por foto o por API)
cobro.registradoSe registra un cobro
stock.bajo_minimoUn artículo cruza por debajo de su stock mínimo
POST https://tu-servidor.com/erpia
Content-Type: application/json
X-ERPIA-Event: factura.emitida
X-ERPIA-Delivery: 6f1c…   (id único de esta entrega)
X-ERPIA-Timestamp: 1789123456
X-ERPIA-Signature: t=1789123456,v1=3f8a…

{
  "id": "6f1c…",
  "evento": "factura.emitida",
  "creado_en": "2026-09-09T10:12:03Z",
  "intento": 1,
  "data": {
    "id": "…", "numero": "F2026-0042", "tipo": "factura", "estado": "confirmada",
    "fecha_emision": "2026-09-09", "total": 2093.30,
    "cliente": { "contacto_id": "…", "nombre": "Rita Gálvez", "nif": "12345678Z", "email": "rita@ejemplo.es" }
  }
}

Verificar la firma

Cada webhook tiene un secreto (whsec_…) que ves en el panel. La firma es HMAC-SHA256(secreto, timestamp + "." + cuerpo) sobre el cuerpo tal cual llega, sin reformatear. Compara en tiempo constante y rechaza timestamps de hace más de 5 minutos.

// Node.js (Express con body en crudo)
import { createHmac, timingSafeEqual } from 'node:crypto'

function verificar(secreto, cabecera, cuerpoCrudo) {
  const { t, v1 } = Object.fromEntries(cabecera.split(',').map(p => p.split('=')))
  if (Math.abs(Date.now() / 1000 - Number(t)) > 300) return false
  const esperada = createHmac('sha256', secreto).update(`${t}.${cuerpoCrudo}`).digest('hex')
  return esperada.length === v1.length && timingSafeEqual(Buffer.from(esperada), Buffer.from(v1))
}
# Python
import hmac, hashlib, time

def verificar(secreto: str, cabecera: str, cuerpo_crudo: bytes) -> bool:
    partes = dict(p.split("=") for p in cabecera.split(","))
    if abs(time.time() - int(partes["t"])) > 300:
        return False
    esperada = hmac.new(secreto.encode(), f"{partes['t']}.".encode() + cuerpo_crudo, hashlib.sha256).hexdigest()
    return hmac.compare_digest(esperada, partes["v1"])

Reintentos. Responde 2xx en menos de 10 segundos. Si no, ERPiA reintenta al minuto, a los 5, a los 30, a las 2 horas y a las 12; después la entrega queda como abandonada y lo ves en el panel. Un webhook con 25 fallos seguidos se apaga solo (lo enciendes de nuevo con un clic). Las entregas pueden llegar más de una vez: usa X-ERPIA-Delivery para descartar duplicados.

Zapier, Make y n8n

Límites y buenas prácticas

¿Necesitas un endpoint que no está?

Escríbenos a hola@erpia.es con lo que quieres conectar. La API crece con lo que la gente integra.