Saltar al contenido principal

Buenas prácticas

Lista de recomendaciones probadas para que tu integración sea robusta, segura y eficiente.


Seguridad​

Almacena las credenciales en variables de entorno​

# .env (nunca subir a Git)
TPVREADY_API_KEY=a3f8d9e2b1c4...
import os
API_KEY = os.environ["TPVREADY_API_KEY"]

Usa un secret manager en producción​

En cloud (AWS, GCP, Azure) o en entornos serios, usa el secret manager nativo (AWS Secrets Manager, GCP Secret Manager, HashiCorp Vault, Doppler…).

Nunca expongas la API Key al cliente final​

Si tu aplicación tiene varios clientes con claves distintas, el cliente NO debe poder ver su propia clave. Solo debe verse un indicador "Conectado ✓".

Implementa rotación periódica​

Avisa al cliente para que rote la clave cada 6-12 meses. Es fácil: regenerar desde el panel + actualizar la nueva clave en tu config.


Robustez​

Implementa timeouts​

Nunca dejes una petición HTTP sin timeout. Si la API tarda demasiado, falla rápido:

requests.get(url, headers=headers, timeout=20)  # 20s razonable

Reintentos con backoff exponencial​

Para errores 5xx o timeouts, reintenta con espera creciente:

import time

def with_retries(fn, max_attempts=4):
for attempt in range(max_attempts):
try:
return fn()
except (ConnectionError, Timeout):
if attempt == max_attempts - 1:
raise
time.sleep(2 ** attempt) # 1s, 2s, 4s, 8s

No reintentes errores 4xx (401, 403, 404, 422) — son problemas de tu petición.

Maneja la pérdida de validez de la credencial​

Tu código debe distinguir entre:

  • Error puntual (5xx) → reintentar
  • Credencial inválida (401) → avisar al cliente, no reintentar
  • Sin permiso (403) → avisar al cliente con instrucciones, no reintentar

Ver Códigos de error → Patrón robusto.

Idempotencia​

Si una petición POST falla con timeout, no sabes si llegó al servidor. Para evitar duplicados:

  • Antes de retry, busca primero si el recurso ya existe (GET /clientes?q=...).
  • Si tu integración inserta lotes, usa identificadores externos únicos (CIF/NIF para clientes, referencia para productos) y trata duplicados como "ya creado".

Eficiencia​

Cachea datos estáticos​

El catálogo de productos, las tarifas y los maestros (formas de pago, países, IVA) cambian poco. Cáchealos localmente y refresca cada N minutos:

@lru_cache(maxsize=1)
def get_catalogo():
return llamar_api("GET", "/productos")

# Invalidar cada 10 min
def get_catalogo_fresco():
if cache_expirado():
get_catalogo.cache_clear()
return get_catalogo()

Paginación inteligente​

Para listados grandes, no pidas page_size demasiado alto: 100-200 es buen equilibrio entre velocidad y carga del servidor.

Solicita solo lo que necesitas​

Si solo necesitas listar nombres de clientes, usa GET /clientes/select (formato ligero) en lugar de GET /clientes (objeto completo).

Evita polling agresivo​

Si necesitas estar al día de cambios:

  • ✅ Polling razonable: cada 1-5 minutos
  • ✅ Solo lo que pudo cambiar: filtra ?modificado_desde=<ultima_sync>
  • ❌ Nunca: cada 1-10 segundos a un endpoint pesado
Webhooks en el roadmap

Los webhooks (notificaciones push cuando algo cambia en TPVReady) están planificados. Cuando estén disponibles, son la forma correcta de reaccionar a eventos en tiempo real sin polling.


Observabilidad​

Loguea peticiones y respuestas (sin la API Key)​

logger.info(
"TPVReady call",
extra={
"method": method,
"path": path,
"status": resp.status_code,
"duration_ms": (time.time() - start) * 1000,
# ❌ NO loguees la API Key
},
)

Mide latencia y tasa de error​

Mantén métricas:

  • p50/p95/p99 de latencia por endpoint
  • Tasa de errores 5xx
  • Tasa de 401/403

Si la tasa de 401 sube de golpe → probablemente una clave de un cliente se revocó.

Alerta en errores persistentes​

Si una integración con un cliente concreto da 401 repetidamente durante > 1 hora, notifica a tu soporte/al cliente. No dejes el error en silencio.


UX hacia tu cliente final​

Mensajes claros, no técnicos​

❌ "Error 403: scope 'productos:read' missing"

✅ "Tu integración no puede acceder al catálogo de productos. Pídele a tu administrador que añada el permiso 'Productos → READ' en TPVReady → Configuración → API Keys."

Indica qué scopes pides y por qué​

Cuando un cliente conecte tu integración, explícale claramente:

Para que la integración funcione, necesita:

  • Clientes → READ: para identificar quién escribe por WhatsApp.
  • Productos → READ: para mostrar precios actualizados en las conversaciones.

No pedimos permisos de escritura ni acceso a facturas.

Tester de conexión​

Incluye un botón "Probar conexión" en tu UI que:

  1. Llame a GET /auth/me (si usas JWT) o a un endpoint trivial con la API Key.
  2. Verifique que devuelve 200.
  3. Muestre OK o el error claro al cliente.

Anti-patrones que evitar​

❌ Mal✅ Bien
Hardcodear la API Key en el códigoCargarla de env/secret manager
Reintentar 401/403 con backoffReintentar solo 5xx
Pedir paginación de 1000 itemsPáginas de 100-200
Loguear el body de errores incluyendo API KeysOfuscar/excluir credenciales del log
Polling cada segundoPolling con frecuencia adecuada o webhooks
Mostrar "Error 500" al usuario final"Tuvimos un problema, lo estamos solucionando"
Una sola API Key para varios clientesUna clave por empresa cliente