Saltar al contenido principal

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.

Ver detalles de scopes →

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

Nunca hagas esto
  • ❌ 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=...).
Sí haz esto
  • ✅ 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ónCómo se detectaQué hacer
Clave pausada o inválida401 UnauthorizedNotificar al cliente, no reintentar
Clave sin scope suficiente403 ForbiddenPedir al cliente que añada el scope desde su panel
Empresa suspendida (impago)401 UnauthorizedMostrar 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.