API para desarrolladores

Lee y crea datos de una empresa desde tu tienda online, tu CRM o tus scripts, y recibe avisos firmados cuando pasa algo.

Autenticación

Un administrador crea la clave en Configuración → API y webhooks. Cada clave da acceso a una empresa, con permiso de solo lectura o de lectura y escritura. Envíala en cada petición:

curl https://matheuserp.es/api/v1/empresa \
  -H "Authorization: Bearer sk_..."
  • Respuestas en JSON. Los importes van en céntimos (12345 = 123,45 €) y las fechas en AAAA-MM-DD.
  • Errores: { "error": "…" } con 401 (clave), 403 (permiso), 402 (cuenta en solo lectura), 404, 422 (datos) o 429 (más de 120 peticiones por minuto).
  • Las facturas emitidas no se modifican ni se borran por la API, igual que en la app.

Operaciones

GET/api/v1/empresaComprueba la clave: empresa y permiso.
GET/api/v1/contactos?tipo=cliente|proveedor&q=Clientes o proveedores.
POST/api/v1/contactosAlta de cliente o proveedor: { tipo, nombre, nif, email?, telefono?, direccion?, codigo_postal?, ciudad?, provincia?, pais? }
GET/api/v1/productos?q=Productos y servicios.
GET/api/v1/facturas?desde=AAAA-MM-DD&hasta=AAAA-MM-DD&q=Facturas emitidas (por defecto, las del trimestre en curso).
GET/api/v1/facturas/{id}Una factura con sus líneas.
GET/api/v1/facturas/{id}/pdfEl PDF de la factura.
POST/api/v1/facturasCrea una factura en borrador; con "emitir": true la emite con el siguiente número.
GET/api/v1/gastos?desde=&hasta=&q=Facturas recibidas y gastos registrados.
GET/api/v1/impuestos/{modelo}?periodo=2026-3TResultado de un modelo (303, 130, 111…) en un periodo.

Ejemplo: crear y emitir una factura.

curl -X POST https://matheuserp.es/api/v1/facturas \
  -H "Authorization: Bearer sk_..." -H "Content-Type: application/json" \
  -d '{ "cliente_id": 12, "emitir": true,
        "lineas": [{ "concepto": "Pedido web 1043", "cantidad": 1, "precio_cents": 4900, "iva_pct": 21 }] }'

Webhooks

Añade una dirección https en Configuración → API y webhooks y elige los eventos. Te enviamos un POST con este cuerpo:

{ "evento": "factura.emitida", "empresa_id": 3, "fecha": "2026-10-17T09:30:00.000Z",
  "datos": { "id": 81, "numero": "2026-0042", "total_cents": 14310, ... } }
  • factura.emitida: factura emitida.
  • factura.cobrada: factura cobrada del todo.
  • gasto.registrado: gasto o factura recibida registrada.
  • contacto.creado: cliente o proveedor creado.
  • pedido.recibido: pedido a proveedor recibido.

Cada envío lleva las cabeceras X-Evento, X-Entrega (identificador, para no procesarlo dos veces) y X-Firma: t=<segundos>,v1=<hex>, donde v1 es el HMAC-SHA256 de t + "." + cuerpo con el secreto del webhook. Comprueba la firma y rechaza las de más de 5 minutos:

import { createHmac, timingSafeEqual } from "crypto";

function firmaValida(secreto, cuerpo, cabecera) {
  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}.${cuerpo}`).digest("hex");
  return timingSafeEqual(Buffer.from(esperada), Buffer.from(v1));
}

Responde con un código 2xx en menos de 8 segundos. Si no, reintentamos con espera creciente (hasta 8 intentos en algo más de dos días).