Integra la facturación Veri*Factu de tus clientes con una API REST.
Contactos, productos, series y facturas — la misma lógica que usa la app de Kullqi, disponible por HTTP con clave de API. La cadena de registro y el envío a la AEAT se aplican igual, la llames desde donde la llames.
# sustituye sk_live_... por tu propia clave, generada en app.kullqi.com/api-keys curl -X POST https://api.kullqi.com/v1/contacts \ -H "Authorization: Bearer sk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \ -H "Content-Type: application/json" \ -d '{ "type": "CUSTOMER", "legalName": "Comercial Ejemplo SL", "taxId": "B12345674", "email": "facturacion@ejemplo.com" }' # respuesta — 201 Created { "id": 42, "type": "CUSTOMER", "legalName": "Comercial Ejemplo SL", "taxId": "B12345674", "archived": false }
Autenticación
Cada petición a /v1/** lleva tu clave en la cabecera Authorization, como token Bearer. Genera y revoca claves desde Claves de API en tu cuenta — solo un ADMIN puede hacerlo, y la clave se muestra una única vez al crearla (guárdala entonces; Kullqi solo conserva su hash, nunca el valor).
Authorization: Bearer sk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Cada clave lleva uno o varios scopes — permisos por recurso, independientes del rol del usuario que la creó. Una petición a un endpoint sin el scope necesario recibe 403 Forbidden.
| Scope | Permite |
|---|---|
| contacts:read | Leer y listar contactos. |
| contacts:write | Crear, modificar y archivar contactos. |
| products:read | Leer y listar productos del catálogo. |
| products:write | Crear y modificar productos. |
| invoices:read | Leer y listar facturas, series y su PDF. |
| invoices:write | Crear borradores y emitir facturas. |
Ciclo de vida de una factura
Emitir una factura son dos pasos separados a propósito: crear el borrador nunca tiene efecto fiscal; emitirlo sí — asigna número de serie, encadena el registro y dispara el envío real a la AEAT (Veri*Factu). Ningún endpoint combina ambas cosas en una sola llamada.
POST /v1/invoices
Crea un borrador (status: "DRAFT") con sus líneas. Sin número, sin efecto fiscal, se puede leer y descartar libremente. Requiere Idempotency-Key — ver más abajo.
POST /v1/invoices/{id}/issue
Emite el borrador contra una serie (seriesId). A partir de aquí la factura es inalterable: número asignado, registro encadenado y envío a la AEAT en marcha.
Idempotencia obligatoria al crear facturas
POST /v1/invoices exige la cabecera Idempotency-Key — un identificador que generas tú (por ejemplo, un UUID por intento de creación desde tu sistema). Repetir la misma petición con la misma clave nunca crea un segundo borrador: devuelve el mismo recurso ya creado.
Sin Idempotency-Key, la petición falla con 400 Bad Request antes de tocar nada — no es opcional. Una factura de verdad no se puede deshacer con un simple DELETE, así que un reintento de red por tu parte nunca debe poder duplicarla.
curl -X POST https://api.kullqi.com/v1/invoices \ -H "Authorization: Bearer sk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \ -H "Idempotency-Key: 8f14e45f-ceea-4c9c-8b3d-4a9e5f1c2b90" \ -H "Content-Type: application/json" \ -d '{ "contactId": 42, "invoiceType": "F1", "lines": [ { "description": "Consultoría", "quantity": 1, "unitPrice": 100.00, "taxRate": 21 } ] }' # primera llamada → 201 Created, id: 17 # repetir EXACTAMENTE la misma Idempotency-Key → 200 OK, mismo id: 17
Límites de uso
Pensados para integraciones reales, no para scraping ni para sustituir el uso normal de la app.
| Límite | Valor |
|---|---|
| Cuota diaria por cuenta (tenant) | 5.000 peticiones / día natural |
| Ritmo sostenido (gateway) | 20 peticiones / segundo |
| Ráfaga máxima (gateway) | 40 peticiones |
Superar la cuota diaria devuelve 429 Too Many Requests con un cuerpo { "message": "..." }; el contador se reinicia a medianoche.
Recursos disponibles
Todas las rutas cuelgan de https://api.kullqi.com. Los cuerpos y campos son exactamente los mismos que usa la propia app de Kullqi — nada simplificado ni recortado para la API pública.
Contactos
| Método | Ruta | Scope | Descripción |
|---|---|---|---|
| POST | /v1/contacts | contacts:write | Crear un contacto (cliente o proveedor). |
| GET | /v1/contacts | contacts:read | Listar contactos, con búsqueda y paginación. |
| GET | /v1/contacts/{id} | contacts:read | Obtener un contacto. |
| PUT | /v1/contacts/{id} | contacts:write | Actualizar un contacto. |
| DELETE | /v1/contacts/{id} | contacts:write | Archivar un contacto (no se elimina el histórico). |
Productos
| Método | Ruta | Scope | Descripción |
|---|---|---|---|
| POST | /v1/products | products:write | Crear un producto o servicio del catálogo. |
| GET | /v1/products | products:read | Listar productos, con búsqueda y paginación. |
| GET | /v1/products/{id} | products:read | Obtener un producto. |
| PUT | /v1/products/{id} | products:write | Actualizar un producto. |
Series de facturación
| Método | Ruta | Scope | Descripción |
|---|---|---|---|
| GET | /v1/invoice-series | invoices:read | Listar las series disponibles (necesarias para emitir). |
Solo lectura en esta versión de la API: las series se crean y configuran desde la app.
Facturas
| Método | Ruta | Scope | Descripción |
|---|---|---|---|
| POST | /v1/invoices | invoices:write | Crear un borrador. Exige Idempotency-Key. |
| POST | /v1/invoices/{id}/issue | invoices:write | Emitir el borrador — número, cadena de registro y envío a la AEAT. |
| GET | /v1/invoices | invoices:read | Listar facturas, con filtros por estado, serie, fechas, contacto. |
| GET | /v1/invoices/{id} | invoices:read | Obtener una factura, con su hash, QR y estado ante la AEAT. |
| GET | /v1/invoices/{id}/pdf | invoices:read | Descargar el PDF con el QR de verificación oficial. |
Fuera de esta versión de la API: rectificar, anular, registrar cobros y enviar por email — de momento solo desde la app de Kullqi.
Errores
Códigos HTTP estándar. Los errores de validación propios de /v1 devuelven un cuerpo JSON simple: { "message": "..." }.
| Código | Significado |
|---|---|
400 | Petición inválida — por ejemplo, falta Idempotency-Key en la creación de una factura. |
401 | Clave ausente, mal formada, revocada o expirada. |
403 | La clave es válida pero no tiene el scope necesario para esta ruta. |
404 | El recurso no existe o no pertenece a tu cuenta. |
429 | Cuota diaria o límite de ritmo superado. |
Genera tu clave y haz tu primera llamada
Se muestra una sola vez al crearla — cópiala en ese momento.
Ir a Claves de API