Documentación para integradores
Esta guía está dirigida a desarrolladores que van a conectar su aplicación con TPVReady.
Si eres un cliente de TPVReady que quiere generar una API Key, consulta API Keys.
Visión general
TPVReady expone una API REST sobre HTTPS. La autenticación máquina-a-máquina se realiza mediante API Keys que el cliente genera desde su panel de TPVReady y comparte contigo.
URL base:
https://api.tpvready.es/api
Cabecera de autenticación:
X-API-Key: <clave_proporcionada_por_el_cliente>
Formato: todas las respuestas son JSON con codificación UTF-8.
Autenticación
Todas las peticiones a endpoints protegidos deben incluir la cabecera X-API-Key.
Ejemplo: listar clientes
cURL
curl https://api.tpvready.es/api/clientes \
-H "X-API-Key: a3f8d9e2b1c4f7e6a2d9c8b5e1f4a7d2b9c6e3f8d1e4a7b2c5f8d3e6a9b4c1d7"
Python (requests)
import requests
API_BASE = "https://api.tpvready.es/api"
API_KEY = "a3f8d9e2b1c4f7e6a2d9c8b5e1f4a7d2b9c6e3f8d1e4a7b2c5f8d3e6a9b4c1d7"
resp = requests.get(
f"{API_BASE}/clientes",
headers={"X-API-Key": API_KEY},
timeout=20,
)
resp.raise_for_status()
clientes = resp.json()
JavaScript (fetch)
const API_BASE = "https://api.tpvready.es/api";
const API_KEY = "a3f8d9e2b1c4f7e6a2d9c8b5e1f4a7d2b9c6e3f8d1e4a7b2c5f8d3e6a9b4c1d7";
const resp = await fetch(`${API_BASE}/clientes`, {
headers: { "X-API-Key": API_KEY },
});
if (!resp.ok) throw new Error(`HTTP ${resp.status}`);
const clientes = await resp.json();
Almacenamiento de la clave
- Nunca incluyas la clave en código fuente versionado.
- Cárgala desde una variable de entorno o secret manager.
- Si la clave se filtra, el cliente puede regenerarla desde su panel; tu integración deberá actualizarse con la nueva.
Permisos (scopes)
Cada API Key tiene permisos granulares definidos por el cliente. Los permisos se expresan como entidad:acción donde:
- Entidades:
clientes,productos,proveedores,presupuestos,pedidos,albaranes,facturas,compras,tickets,proyectos. - Acciones:
read(listar y ver detalle),write(crear, modificar, eliminar).
Si tu petición usa una clave sin el permiso necesario, TPVReady responderá con 403 Forbidden.
Indicar al cliente qué permisos necesitas
Para que tu integración funcione, pídele al cliente que al generar la API Key marque exactamente los permisos que necesitas. Por ejemplo, una integración de chatbot que solo necesita consultar clientes y productos requiere:
- ✅
clientes:read - ✅
productos:read
No pidas más permisos de los necesarios.
Endpoints disponibles
La API se irá ampliando progresivamente. La siguiente lista refleja únicamente los endpoints abiertos a integración por API Key en este momento. Otros endpoints existen pero requieren JWT humano y no son accesibles vía API Key.
Clientes
GET /clientes
Lista los clientes de la empresa.
Permiso requerido: clientes:read
Parámetros de consulta (opcionales):
| Parámetro | Tipo | Descripción |
|---|---|---|
q | string | Búsqueda por nombre, CIF/NIF, email o teléfono. |
activo | bool | true para solo activos, false para inactivos. |
page | int | Página (por defecto 1). |
page_size | int | Elementos por página (por defecto 50). |
Ejemplo:
curl "https://api.tpvready.es/api/clientes?q=garcia&activo=true&page=1" \
-H "X-API-Key: $TPV_KEY"
Respuesta (200):
{
"items": [
{
"token": "8f4a9e2b-1c3d-4e5f-9a8b-7c6d5e4f3a2b",
"nombre_fiscal": "GARCIA LOPEZ S.L.",
"nombre_comercial": "Farmacia García",
"nif": "B12345678",
"email": "info@farmacia-garcia.es",
"telefono": "+34911223344",
"telefono2": null,
"telefono3": null,
"direccion": "Calle Mayor 12",
"codpostal": "10600",
"localidad": "Plasencia",
"provincia": "Cáceres",
"regimen_iva": "general",
"activo": true
}
],
"total": 1,
"page": 1,
"page_size": 50
}
GET /clientes/{token}
Detalle de un cliente concreto.
Permiso requerido: clientes:read
Parámetro de ruta: token — el UUID del cliente.
Respuesta (200): objeto completo del cliente, incluyendo direcciones y contactos.
Errores:
404— Cliente no encontrado.
GET /clientes/{token}/movimientos
Histórico de documentos (facturas, pedidos, albaranes, presupuestos) del cliente.
Permiso requerido: clientes:read
Respuesta (200):
{
"facturas": [ /* ... */ ],
"pedidos": [ /* ... */ ],
"albaranes": [ /* ... */ ],
"presupuestos": [ /* ... */ ]
}
GET /clientes/select
Versión ligera para usar en selectores/autocompletes (devuelve solo token, nombre, nif).
Permiso requerido: clientes:read
Productos
GET /productos
Lista del catálogo de productos.
Permiso requerido: productos:read
Parámetros de consulta (opcionales):
| Parámetro | Tipo | Descripción |
|---|---|---|
q | string | Búsqueda por referencia, nombre o EAN. |
activo | bool | Filtrar por activos/inactivos. |
familia_id | int | Filtrar por familia. |
page | int | Página. |
page_size | int | Elementos por página. |
Ejemplo:
curl "https://api.tpvready.es/api/productos?q=ibuprofeno" \
-H "X-API-Key: $TPV_KEY"
Respuesta (200):
{
"items": [
{
"token": "f7e3a9c1-8b2d-4f5e-a6c7-d9e8f7a6b5c4",
"referencia": "IBU-600",
"nombre": "Ibuprofeno 600 mg 40 comprimidos",
"descripcion": "Antiinflamatorio no esteroideo...",
"ean": "8470001234567",
"precio": 5.95,
"stock_total": 42,
"activo": true
}
],
"total": 1,
"page": 1,
"page_size": 50
}
El campo precio se devuelve IVA incluido y corresponde a la tarifa por defecto de la empresa.
GET /productos/{token}
Detalle de un producto, incluyendo todas sus tarifas y stock por almacén.
Permiso requerido: productos:read
Códigos de error
La API usa los códigos HTTP estándar y devuelve un cuerpo JSON con el formato:
{ "detail": "Mensaje descriptivo del error" }
| Código | Significado | Cuándo ocurre |
|---|---|---|
| 200 | OK | Petición correcta. |
| 400 | Bad Request | Parámetros mal formados o validación fallida. |
| 401 | Unauthorized | Falta X-API-Key, clave inválida, revocada o pausada. |
| 403 | Forbidden | La clave no tiene el scope necesario para esta operación. |
| 404 | Not Found | Recurso solicitado no existe o no pertenece a la empresa. |
| 422 | Unprocessable Entity | Validación de schema fallida (ej. tipo de dato incorrecto). |
| 429 | Too Many Requests | Reservado para rate limiting (no aplicado actualmente). |
| 500 | Internal Server Error | Error inesperado. Reintenta más tarde o contacta soporte. |
Ejemplo de 403 (sin permiso)
{
"detail": "La API Key no tiene permiso 'productos:read'. Solicita al administrador que añada el permiso o usa una clave con los scopes adecuados."
}
Manejo recomendado de errores
import requests
def llamar_api(metodo, ruta, **kwargs):
resp = requests.request(
metodo,
f"https://api.tpvready.es/api{ruta}",
headers={"X-API-Key": API_KEY},
timeout=20,
**kwargs,
)
if resp.status_code == 401:
raise RuntimeError("API Key inválida o revocada. Solicita una nueva al cliente.")
if resp.status_code == 403:
detalle = resp.json().get("detail", "")
raise RuntimeError(f"Falta permiso: {detalle}")
if resp.status_code >= 500:
# Reintentar con backoff exponencial
raise RuntimeError("Error del servidor, reintentar más tarde.")
resp.raise_for_status()
return resp.json()
Convenciones
Identificadores
Todos los recursos se exponen con un token UUID (no con IDs numéricos). Usa siempre los tokens en las URLs.
✅ GET /clientes/8f4a9e2b-1c3d-4e5f-9a8b-7c6d5e4f3a2b
❌ GET /clientes/142
Fechas y horas
Formato ISO 8601 en UTC: 2026-05-25T14:30:00Z.
Paginación
Los endpoints de listado devuelven:
{
"items": [ /* ... */ ],
"total": 1234,
"page": 1,
"page_size": 50
}
Para iterar todos los resultados, incrementa page hasta que items venga vacío.
Aislamiento por empresa
Cada API Key está vinculada a una única empresa. Solo verás datos de esa empresa; no es necesario filtrar por empresa_id en las peticiones (ya se aplica de forma transparente).
Buenas prácticas
✅ Cachea los datos estáticos. El catálogo de productos suele cambiar poco; cachea localmente y refresca cada N minutos en vez de pedir el catálogo completo en cada interacción.
✅ Reintentos con backoff. Para errores 5xx, reintenta 2-3 veces con espera creciente (1s, 2s, 4s).
✅ Identifica tu aplicación. Aunque no es obligatorio, te recomendamos enviar un User-Agent descriptivo:
User-Agent: Whatafarma/1.4.2 (+contacto@whatafarma.com)
Esto facilita el soporte si surge algún problema.
✅ Maneja la revocación con elegancia. Si recibes un 401 persistente, notifica al cliente para que regenere la clave en lugar de bloquear el servicio en silencio.
❌ No hagas polling agresivo. Si necesitas saber cuándo cambia algo, consulta con frecuencia razonable (cada 1-5 minutos, no cada segundo).
Soporte
Si tienes dudas sobre la integración:
- 📧 soporte@extremanet.com — Soporte técnico general.
- 📧 magarcia@extremanet.com — Cuestiones específicas de integración.
Indica siempre:
- Nombre de tu aplicación.
- Empresa cliente de TPVReady con la que estás integrando.
- Endpoint que estás llamando.
- Código y cuerpo de la respuesta recibida.
Roadmap
Los siguientes endpoints están en desarrollo y se irán habilitando próximamente:
GET /facturas— Lectura de facturas emitidas.GET /pedidos— Lectura de pedidos de venta.POST /clientes— Alta de clientes desde integraciones.POST /pedidos— Creación de pedidos desde chatbot/portal.- Webhooks de eventos (cliente creado, factura pagada, etc.).
Si necesitas alguno de estos endpoints antes de que se publiquen, escríbenos a soporte indicando tu caso de uso.