Documentación de la API

Cómo conectar tu sistema: clientes, consumo, documentos, presupuestos y albaranes.

URL base de la API: https://ticket.quantumpyme.com/api/v1 · versión 1.5.0

Cada petición lleva tu clave en Authorization: Bearer …. Puedes crearla en Claves de API. Importa la especificación OpenAPI en Postman, Insomnia o tu generador de clientes.

API v1 — Guía para partners

API REST para gestionar desde tu sistema a tus clientes de Quantum Contable, consultar su consumo, y subir, sincronizar y revisar sus documentos. La especificación completa y siempre al día está en `openapi.yaml` (OpenAPI 3.1: impórtala en Postman, Insomnia o genera un cliente con tu lenguaje). Esta guía explica cómo se usa.

Base: https://ticket.quantumpyme.com/api/v1

1. Primeros pasos

  1. Contrato. Para escribir o leer datos de tus clientes hace falta el contrato de encargo del tratamiento (art. 28 RGPD) firmado con QuantumPYME. Lo firma el administrador de tu equipo desde el apartado «Contrato» de tu panel, en unos minutos. Sin él, esos permisos no se pueden crear y devuelven 403 contract_required.
  2. Clave. En tu panel de socio → «Claves de API», crea una clave con los permisos que necesites. Se muestra una sola vez: guárdala como un secreto (gestor de secretos o variable de entorno; nunca en el código ni en los logs).
  3. Prueba.
curl https://ticket.quantumpyme.com/api/v1/me -H "Authorization: Bearer qt_live_xxxxxxxx_…"

Devuelve tu partner, los permisos de la clave y el límite de peticiones.

2. Permisos de la clave

PermisoPara quéContrato
clients:readListar y ver clientesNo
clients:writeCrear y modificar clientes, desactivarlos y vincular su WhatsAppSí
usage:readConsumo y saldoNo
documents:readLeer documentosSí
documents:writeSubir PDF o imágenes para leerlos con IA, enviar documentos con los datos ya extraídos, y corregir, confirmar o descartar documentosSí
webhooks:manageAvisos automáticosSí
commercial:readLeer presupuestos y albaranesSí
commercial:writeCrear y modificar presupuestos y albaranesSí
messages:writeReenviar a nuestro asistente lo que escribe o manda un cliente (chatbot)Sí

Da a cada clave solo lo que necesita. Puedes limitarla por IP y ponerle caducidad desde el panel. Por defecto caduca al año: cuando falte poco, crea otra y revoca la anterior.

No hay entorno de pruebas. Todas las claves son qt_live_… y actúan sobre datos reales (los clientes que crees cuentan, y sus documentos gastan saldo). Para probar, crea clientes con un externalId reconocible (por ejemplo PRUEBA-…) y desactívalos al terminar.

3. Convenciones

  • Paginación: limit (1–100, por defecto 50) y cursor. Cada lista devuelve { "data": [...], "nextCursor": "…" | null }; sigue pidiendo con cursor=<nextCursor> hasta que sea null.
  • Errores: { "error": { "code", "message", "requestId", "details"? } } con el código HTTP correspondiente. Programa contra code, no contra message. Guarda el requestId (también va en la cabecera X-Request-Id) si contactas con soporte.
  • Límite: 60 peticiones por minuto y clave. Al pasarte recibes 429 rate_limited: espera y reintenta. La subida de documentos tiene sus propios límites (ver el apartado 6).
  • Aislamiento: solo ves y modificas clientes de tu partner. Un cliente o documento de otro partner responde 404, igual que uno inexistente.
  • Fechas: ISO 8601 en UTC; las fechas de documento, AAAA-MM-DD.

Códigos de error frecuentes en clientes:

CódigoHTTPSignificado
invalid_parameter400Un campo falta o no es válido (el mensaje dice cuál). El cuerpo es estricto: un campo desconocido es un error
plan_required / invalid_plan400Con comisión el plan es obligatorio y debe ser de su tipo (cliente o gestoría)
plans_not_applicable409Con bolsas no hay planes
external_id_in_use409Ya tienes un cliente con ese externalId; error.details.clientId es el existente
email_in_use409El email ya está registrado en Quantum Contable. Si se repite muchas veces seguidas (más de 20 al día), 429 rate_limited
whatsapp_already_linked409El cliente ya tiene un WhatsApp vinculado
client_inactive409El cliente está desactivado
partner_suspended409Tu cuenta de partner está suspendida
client_not_found404No existe o no es tuyo

4. Flujo: dar de alta un cliente que trabajará por WhatsApp

El cliente no entra al panel: tú lo das de alta desde tu sistema y él manda sus tickets por WhatsApp.

1. Crear el cliente (clients:write):

curl -X POST https://ticket.quantumpyme.com/api/v1/clients \
  -H "Authorization: Bearer $QT_KEY" -H "Content-Type: application/json" \
  -d '{ "nombre": "Taller Rodríguez SL", "email": "info@tallerrodriguez.es", "plan": "starter", "externalId": "ERP-1042", "limiteDocsMes": 80 }'
  • Con comisión, plan es obligatorio (starter, professional, business; para una gestoría tipo: "gestoria" y gestorias_s|m|l). Con bolsas no lleva plan.
  • externalId es tu identificador. Hace segura la reintentación: si la petición se corta y la repites, no se crea un duplicado; recibes 409 external_id_in_use con el clientId que ya existe.
  • limiteDocsMes es el tope mensual de ese cliente (0 = sin límite; si no lo pones, rige el límite por defecto de tu cuenta).
  • No se envía ninguna invitación al cliente.

2. Vincular su WhatsApp. El número no se fija desde tu sistema: lo vincula el propio cliente enviando un código desde su móvil, para que nadie quede vinculado a un número que no es suyo. Pide el código:

curl -X POST https://ticket.quantumpyme.com/api/v1/clients/CLIENT_ID/whatsapp-link -H "Authorization: Bearer $QT_KEY"
# → { "code": "K7M2QX", "expiresAt": "2026-10-20T16:30:00.000Z", "whatsappNumber": "+34876084424" }

Dile al cliente que envíe ese código desde su móvil por WhatsApp al número whatsappNumber. Caduca en 30 minutos; si pides otro, el anterior deja de valer. Cuando el cliente lo envía, su número queda vinculado y ya puede mandar fotos o PDF de sus tickets y facturas. Comprueba whatsappVinculado en GET /clients/{id}.

whatsappNumber es tu número propio si lo tienes activo y, si no, el de Quantum Contable.

3. Gestionarlo después: PATCH /clients/{id} (nombre, sector, externalId, plan, límite; telefono: null desvincula el WhatsApp), POST /clients/{id}/deactivate y /reactivate. El email y el tipo no se cambian por la API.

5. Consumo y saldo (usage:read)

  • GET /usage: tu modelo (bag o commission), clientes activos y totales, documentos del periodo y, con bolsas, el saldo (bag.balance), el estado (ok, gracia, agotada, sin_bolsa) y la próxima caducidad.
  • GET /usage/clients y GET /clients/{id}/usage: documentos del periodo y límite efectivo de cada cliente (limitSource: client, partner_default o none).

Consumo por mes (para facturar a tus clientes). Añade ?month=2026-11 (mes natural, hora de Madrid) a cualquiera de los tres endpoints y cada respuesta incluye month: { month, documents, byChannel } con los documentos de ese mes y de qué canal vinieron (whatsapp, api, email, factura). Con /usage/clients?month=… recorres a todos tus clientes (con nextCursor) y obtienes la tabla para cobrar. El histórico empieza el día en que se activó esta función; los meses anteriores no están.

Mensajes de WhatsApp (solo con bolsas). Cada mes están incluidos 1.000 mensajes de WhatsApp salientes (las respuestas que enviamos a tus clientes por WhatsApp). Desde el 1.001, cada mensaje de más cuesta 0,021 € sin IVA y se descuenta de tu bolsa, en documentos equivalentes, al cierre del mes (importe ÷ precio por documento de tu bolsa, redondeado hacia arriba). Los mensajes que iniciamos nosotros fuera de las 24 h de una conversación no entran en los incluidos y se cobran desde el primero. Los mensajes por API (/messages) y por correo no cuentan. Con ?month= en GET /usage recibes whatsapp: { sent, included, billable, pricePerMessageEur, amountEur, documentsDeducted, closed }; también lo ves en el panel, en Bolsas. Te avisamos por correo al llegar a 800 y al superar los 1.000.

Con bolsas, el estado gracia significa que te has quedado sin saldo pero los documentos siguen entrando durante el margen pactado: te conviene comprar otra bolsa antes de agotada, cuando sus clientes dejan de poder enviar. Se avisa al 20 % del saldo.

6. Documentos y webhooks

  • Documentos: lista, filtros y sincronización incremental con actualizadoDesde; subida de archivos y revisión (corregir, confirmar, descartar).
  • Webhooks: avisos firmados (HMAC-SHA256) cuando un documento se crea o cambia.

Flujo: subir un documento desde tu aplicación y revisarlo

Para que tu cliente trabaje solo en tu aplicación, sin entrar al panel de Quantum Contable. Permiso documents:write (y documents:read para consultar).

  1. Subes el archivo: POST /clients/{clientId}/documents, en multipart/form-data con el archivo en el campo file (PDF, JPG, PNG o WebP, hasta 10 MB). Respondemos al momento (202) con el documentId y el estado procesando.
  2. Lo leemos con IA (unos segundos). Te llega el webhook document.needs_review (o document.processed), o lo consultas con GET /documents/{documentId}.
  3. Tu usuario revisa los datos en tu aplicación.
  4. Cierras el documento: PATCH /documents/{id} si hay que corregir algo, y después POST /documents/{id}/confirm para darlo por bueno o POST /documents/{id}/exclude para descartarlo.
curl -X POST https://ticket.quantumpyme.com/api/v1/clients/CLIENT_ID/documents \
  -H "Authorization: Bearer $QT_KEY" -H "Idempotency-Key: factura-0042" \
  -F "file=@factura.pdf"
# → 202 { "documentId": "clx…", "estado": "procesando", "paginas": 1, "documentsConsumed": 1, "duplicateOf": null }

Cuánto cuenta. Un PDF de hasta 3 páginas cuenta como 1 documento de tu bolsa o del límite del cliente; con más páginas, 1 por cada bloque de 3 (máximo 30 páginas). documentsConsumed lo indica. Un archivo repetido o uno que no se puede leer no descuenta nada.

Si tu chatbot reenvía lo que escribe tu cliente. POST /clients/{id}/messages (permiso messages:write): con {"text": "…"} nuestro asistente lo interpreta (consultas de cifras, búsqueda de documentos, presupuestos y facturas si el cliente tiene el módulo) y devuelve sus respuestas en replies para que las muestres; nada sale por WhatsApp. Si awaitingReply es true, el asistente ha preguntado algo y el siguiente mensaje de ese cliente es la contestación. Con un archivo (multipart, campo file, text opcional como pie de foto) sigue el flujo de documentos de arriba (202 y webhook).

curl -X POST https://ticket.quantumpyme.com/api/v1/clients/CLIENT_ID/messages \
  -H "Authorization: Bearer $QT_KEY" -H "Content-Type: application/json" -d '{"text":"¿Cuánto llevo gastado este mes?"}'
# → 200 { "replies": [{ "type": "text", "text": "…" }], "awaitingReply": false }

Si ya lees tú los documentos. Envía los datos extraídos en JSON a POST /clients/{id}/documents/data (mismos nombres de campo que GET /documents/{id}: emisor, fecha, numero, lineasIVA, retencionIRPF…). Contesta 201, el documento queda en pendiente_revision y cuenta 1 documento. Un total que no cuadra es 400 total_mismatch; un documento ya registrado es 409 duplicate_document (repite con allowDuplicate: true si es otro distinto).

curl -X POST https://ticket.quantumpyme.com/api/v1/clients/CLIENT_ID/documents/data \
  -H "Authorization: Bearer $QT_KEY" -H "Idempotency-Key: factura-0042" -H "Content-Type: application/json" \
  -d '{"emisor":{"nombre":"Ferretería Pepe","nif":"B12345678"},"fecha":"2026-11-03","numero":"F-0042","lineasIVA":[{"tipo":21,"base":100,"cuota":21}]}'

Por correo del cliente. Cada cliente puede conectar desde su portal («Buzón de correo») una cuenta dedicada a documentos: leemos sus correos nuevos en solo lectura y los PDF o imágenes adjuntos se registran como documentos pendientes de revisión, con la misma regla de cuenta y descuento de tu bolsa. Los ves en GET /documents y en el desglose por canal de /usage?month= (email).

Reintentos. Con la cabecera Idempotency-Key, repetir la petición no duplica nada. Si ese mismo archivo ya estaba registrado para el cliente, recibes 200 con duplicateOf y documentsConsumed: 0.

Límites por clave. 30 subidas por minuto y 10 documentos esperando a procesarse, además de un máximo diario por partner. Si los superas, 429 (rate_limited, too_many_pending o daily_limit) con error.details.retryAfter en segundos. Si vas a cargar un histórico grande, avísanos del volumen.

Estados. procesando → pendiente_revision → confirmado o excluido; error si no se pudo leer (no descuenta nada y puedes volver a enviarlo).

CódigoHTTPSignificado
file_required / invalid_content_type400Falta el archivo o no es multipart/form-data
unsupported_file_type / invalid_pdf400Formato no admitido (se comprueba el contenido, no la extensión) o PDF dañado o con contraseña
too_many_pages400El PDF tiene más de 30 páginas
file_too_large413El archivo supera los 10 MB
quota_exhausted409El cliente o tu bolsa no tienen documentos disponibles
idempotency_key_reused409Esa Idempotency-Key ya se usó con otro archivo u otro cliente
document_locked409Ingreso de una factura emitida desde Quantum Contable: se rectifica, no se edita
multiple_vat_lines / vat_breakdown_missing409No se puede cambiar la base ni el tipo de IVA en ese documento (ver Documentos)
document_not_found404No existe o es de otro partner

Lo que todavía no hace: no hay un webhook para un error de lectura (consúltalo con GET), no se cambia un documento de gasto a ingreso ni al revés, y un documento excluido no se reabre.

Patrón recomendado: webhook para enterarte al momento (document.processed, document.needs_review, document.updated) y una sincronización incremental nocturna con GET /documents?actualizadoDesde=… como red de seguridad.

7. Presupuestos y albaranes

Tus clientes pueden emitir presupuestos y albaranes (desde su panel, por WhatsApp o por tu sistema) y tú los sincronizas por API. Son documentos no fiscales: no entran en la contabilidad ni en VERI*FACTU; solo la factura final cuenta.

Requisito: los presupuestos y albaranes vienen activos en todas las cuentas de cliente. Si a una cuenta se le han quitado, 409 module_not_enabled; pide a QuantumPYME que se los active.

Ciclo de vida

Estados
Presupuestoemitido → aceptado · rechazado · anulado · convertido (en albarán) · facturado
Albaránemitido → entregado · anulado · facturado

Cada documento recibe su número al crearse (P-2026-0001, A-2026-0001): correlativo por cliente, tipo y año, sin huecos; uno anulado conserva su número. «Caducado» no es un estado: es un presupuesto emitido con caducado: true (su validoHasta ya pasó). Solo se modifica mientras está emitido.

Crear (desde tu sistema)

curl -X POST https://ticket.quantumpyme.com/api/v1/clients/CLIENT_ID/quotes \
  -H "Authorization: Bearer $QT_KEY" -H "Content-Type: application/json" \
  -d '{ "cliente": { "nombre": "Construcciones Pérez SA", "nif": "A58818501" },
        "lineas": [{ "concepto": "Reparación del cuadro", "cantidad": 1, "precioUnitario": "450", "tipoIva": 21 }],
        "externalId": "PRE-1042", "numeroExterno": "PRE-1042" }'

Igual para /clients/{id}/delivery-notes (con "valorado": false para un albarán sin precios en el PDF).

Cómo no pisaros los números. Quantum Contable numera los suyos (numeroFormato) y tu sistema los suyos: guarda el tuyo en numeroExterno (único por tipo) y el identificador interno en externalId. Cada documento llega con los dos.

Sincronización en los dos sentidos

  • Tu sistema → Quantum: crea con POST y un externalId. Es seguro reintentar: si ya existe recibes 409 external_id_in_use con error.details.documentId.
  • Quantum → tu sistema: los documentos que el cliente crea desde su panel o por WhatsApp (origen: "manual" o "whatsapp") los recoges con GET /quotes y GET /delivery-notes y actualizadoDesde=<la mayor actualizadoEn que viste>. Cada cambio de estado (aceptado, entregado…) hace que el documento reaparezca. Los avisos por webhook de estos documentos llegarán más adelante: mientras tanto, consulta cada pocos minutos.
  • Cambiar de estado: POST /quotes/{id}/accept|reject|cancel|convert, POST /delivery-notes/{id}/deliver|cancel. convert crea un albarán con las líneas del presupuesto (origenId apunta a él).
  • Facturación: si facturas en tu sistema, marca el documento con POST …/invoiced y la referencia de tu factura (facturaReferencia). Si el cliente factura desde su panel, el documento pasa a facturado.
  • PDF: GET /quotes/{id}/pdf y GET /delivery-notes/{id}/pdf.

Importes como texto decimal ("121.00") para no perder céntimos. Un partner solo ve los documentos de sus clientes creados desde que son suyos.

8. Buenas prácticas

  • Reintenta con espera creciente ante 429 y 5xx; nunca ante 4xx (salvo 429).
  • Guarda el id de Quantum junto a tu externalId.
  • Rota la clave ante cualquier sospecha y revoca las que ya no uses (panel → Claves de API). Si pierdes una clave, avísanos de inmediato.
  • Trata los datos recibidos conforme a tu contrato de encargo: solo para prestar el servicio a cada cliente, con acceso restringido y cifrado en tus sistemas.

Cambios

  • 1.5 (noviembre 2026): consumo por mes y canal (?month=AAAA-MM en /usage, /usage/clients y /clients/{id}/usage, con el bloque whatsapp de los mensajes incluidos y de más); documentos con los datos ya extraídos (POST /clients/{id}/documents/data, 201, Idempotency-Key, 409 duplicate_document, 400 total_mismatch); mensajes de tu chatbot a nuestro asistente (POST /clients/{id}/messages, permiso messages:write). Los clientes pueden además conectar su correo desde su portal y sus adjuntos entran como documentos (canal email). Sin cambios que rompan lo anterior.
  • 1.4 (octubre 2026): el WhatsApp de un cliente ya no se fija con telefono al crearlo o modificarlo: se vincula con el código de whatsapp-link que el cliente envía desde su móvil (telefono: null en PATCH sigue desvinculando). Muchos email_in_use seguidos dan 429 rate_limited. Las claves nuevas caducan al año por defecto.
  • 1.3 (octubre 2026): subida de documentos (POST /clients/{id}/documents, asíncrona, con Idempotency-Key) y revisión (PATCH /documents/{id}, POST /documents/{id}/confirm y /exclude), con el permiso documents:write. GET /documents/{id} devuelve estado: procesando o error mientras una subida no ha terminado.
  • 1.2 (octubre 2026): presupuestos y albaranes (/quotes, /delivery-notes, con alta bajo /clients/{id}/…), con externalId y numeroExterno para sincronizar con tu sistema, y permisos commercial:read y commercial:write.
  • 1.1 (octubre 2026): escritura de clientes (POST/PATCH /clients, deactivate, reactivate), vinculación de WhatsApp (whatsapp-link), consumo (/usage, /usage/clients, /clients/{id}/usage) y permisos clients:write y usage:read. GET /clients devuelve además tipo, plan, limiteDocsMes, docsMes y whatsappVinculado. Especificación OpenAPI.
  • 1.0: lectura de clientes y documentos, y webhooks.

Próximamente: webhooks de presupuestos y albaranes, un aviso por webhook cuando falla la lectura de una subida, y exportaciones (A3, Holded).