Autenticación con API Key
Las API Keys permiten que un servicio externo acceda a TPVReady sin necesidad de un usuario humano. Son ideales para integraciones servidor-a-servidor.
Obtener una API Key
Tú no generas la API Key. La genera el cliente de TPVReady desde su panel y te la entrega.
Si necesitas integrar tu aplicación con varias farmacias o clientes distintos, cada uno te entregará su propia clave. Tu aplicación debe poder gestionar varias claves simultáneamente, una por empresa.
Formato de la petición
Añade la cabecera X-API-Key a cada petición:
GET /api/productos HTTP/1.1
Host: api.tpvready.es
X-API-Key: a3f8d9e2b1c4f7e6a2d9c8b5e1f4a7d2b9c6e3f8d1e4a7b2c5f8d3e6a9b4c1d7
Accept: application/json
Ejemplos
cURL
curl https://api.tpvready.es/api/productos \
-H "X-API-Key: a3f8d9e2b1c4f7e6a2d9c8b5e1f4a7d2b9c6e3f8d1e4a7b2c5f8d3e6a9b4c1d7"
Python (requests)
import os
import requests
API_BASE = "https://api.tpvready.es/api"
API_KEY = os.environ["TPVREADY_API_KEY"]
resp = requests.get(
f"{API_BASE}/productos",
headers={"X-API-Key": API_KEY},
timeout=20,
)
resp.raise_for_status()
productos = resp.json()
JavaScript (fetch)
const API_BASE = "https://api.tpvready.es/api";
const API_KEY = process.env.TPVREADY_API_KEY;
const resp = await fetch(`${API_BASE}/productos`, {
headers: { "X-API-Key": API_KEY },
});
if (!resp.ok) throw new Error(`HTTP ${resp.status}`);
const productos = await resp.json();
PHP
$ch = curl_init('https://api.tpvready.es/api/productos');
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'X-API-Key: ' . getenv('TPVREADY_API_KEY'),
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$resp = curl_exec($ch);
$data = json_decode($resp, true);
Características de las API Keys
No caducan
A diferencia de los JWT, una API Key sigue funcionando hasta que el cliente:
- La pausa temporalmente.
- La regenera (la antigua deja de valer).
- La revoca permanentemente.
Tienen scopes (permisos granulares)
Cada API Key tiene asociados unos permisos por entidad: clientes, productos, facturas… y para cada uno puede tener read, write o nada.
Si intentas usar un endpoint sin el scope necesario, recibirás 403 Forbidden.
Tienen telemetría
El cliente puede ver desde su panel:
- Cuándo fue tu última petición.
- Desde qué IP la hiciste.
- Cuántas llamadas totales has hecho.
Si tu integración deja de funcionar, esto le ayuda a diagnosticar.
Seguridad
Almacenamiento
- ❌ Subir la API Key a un repositorio público de GitHub.
- ❌ Incluirla en código fuente versionado.
- ❌ Compartirla por email, chat o canales no cifrados.
- ❌ Loguearla en archivos de log.
- ❌ Incluirla en URLs (
?api_key=...).
- ✅ Cargarla desde variables de entorno.
- ✅ Usar un secret manager (AWS Secrets, Vault, Doppler, etc.) en producción.
- ✅ Tenerla solo en el servidor, nunca en el cliente (navegador, app móvil).
- ✅ Rotarla periódicamente (cada 6-12 meses como buena práctica).
Si crees que la clave se ha filtrado
Avisa al cliente para que la regenere inmediatamente desde su panel. La clave nueva se la entregará a ti, y la antigua dejará de funcionar al instante.
Tu aplicación nunca debe permitir al usuario final ver la API Key
Si tu aplicación tiene varios clientes con claves distintas, cada cliente solo debe ver "API Key configurada ✓" — no la clave en sí. Esto evita filtraciones accidentales.
Manejar la pérdida de validez
Tu código debe estar preparado para:
| Situación | Cómo se detecta | Qué hacer |
|---|---|---|
| Clave pausada o inválida | 401 Unauthorized | Notificar al cliente, no reintentar |
| Clave sin scope suficiente | 403 Forbidden | Pedir al cliente que añada el scope desde su panel |
| Empresa suspendida (impago) | 401 Unauthorized | Mostrar mensaje claro al cliente |
Ejemplo de manejo robusto:
def call_tpvready(method, path, **kwargs):
resp = requests.request(
method,
f"https://api.tpvready.es/api{path}",
headers={"X-API-Key": API_KEY},
timeout=20,
**kwargs,
)
if resp.status_code == 401:
# Notificar al admin de tu app: la clave del cliente X ya no vale
notificar_clave_invalida(empresa_id)
raise APIKeyInvalida()
if resp.status_code == 403:
detalle = resp.json().get("detail", "")
notificar_falta_scope(empresa_id, detalle)
raise ScopeInsuficiente(detalle)
if resp.status_code >= 500:
# Reintento con backoff (ver Buenas Prácticas)
raise ErrorServidor()
resp.raise_for_status()
return resp.json()
Limitaciones
- Una API Key = una empresa. Si tu aplicación trabaja con varias farmacias, cada una te dará su propia clave.
- No expira automáticamente. Tu aplicación es responsable de pedir rotación al cliente cada cierto tiempo.
- Las claves de admin (con scopes totales) pueden hacer todo. Pide al cliente que use scopes específicos si tu integración no necesita acceso completo.