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