Descripción General
La API de Imagina Energía implementa rate limiting (limitación de tasa) para proteger el servicio contra:
- 🛡️Ataques de Denegación de Servicio (DoS)
- 🔄Uso excesivo de recursos
- 🐛Bucles infinitos en código cliente
- 📊Uso abusivo no intencionado
El sistema limita el número de peticiones que un cliente puede realizar en un período de tiempo específico.
Límites por Defecto
La API implementa dos niveles de límites:
1. Límites por Usuario/IP
Todos los endpoints tienen aplicados los siguientes límites individuales:
| Período | Límite | Descripción |
|---|---|---|
| Por hora | 200 peticiones | Límite individual para uso normal |
| Por minuto | 50 peticiones | Protección individual contra ráfagas |
2. Límites Globales (Aplicación Completa)
Además, existe un límite global que protege el servidor de sobrecarga total:
| Período | Límite | Descripción |
|---|---|---|
| Por hora | 5,000 peticiones | Límite total para todos los usuarios |
| Por minuto | 1,000 peticiones | Protección global contra ráfagas |
- Los límites por usuario se aplican individualmente (cada usuario tiene su cuota)
- Los límites globales se aplican a TODA la aplicación (compartidos entre todos)
- Si se alcanza el límite global, todos los usuarios recibirán error 429
- Los límites globales son más altos para permitir uso simultáneo de múltiples usuarios
¿Cómo Interactúan los Límites?
Si haces 60 peticiones en un minuto:
❌ Rechazada - Excedes tu límite individual (50/min)
Si 15 usuarios hacen 50 peticiones cada uno simultáneamente (750 total):
✅ OK - Dentro del límite global (1000/min)
Si 25 usuarios hacen 50 peticiones cada uno simultáneamente (1250 total):
❌ Rechazada - Excede el límite global (1000/min)
⚠️ Afecta a TODOS los usuarios, incluso los que no han alcanzado su límite individual
Límites por Endpoint
Algunos endpoints críticos tienen límites más estrictos:
Endpoints de Contratación
POST /contrato/residencial/c1
POST /contrato/empresa/c1
Límites:
- 10 peticiones por minuto
- 50 peticiones por hora
Razón: Creación de contratos es una operación costosa que involucra:
- Validaciones complejas
- Credit check externo
- Creación en sistema Neuro
- Envío a firma electrónica
Endpoints de Consulta
GET /contrato/{id_contrato}
GET /contratos
GET /tarifas
Límites:
- 100 peticiones por minuto
- 500 peticiones por hora
Razón: Operaciones de solo lectura más ligeras.
Endpoints de Documentos
POST /documento
GET /documento/{id}
Límites:
- 20 peticiones por minuto (POST)
- 100 peticiones por minuto (GET)
Razón: La subida de documentos consume ancho de banda y almacenamiento.
Headers de Rate Limit
Cada respuesta incluye headers informativos sobre el estado de tu límite:
| Header | Descripción | Ejemplo |
|---|---|---|
| X-RateLimit-Limit | Número máximo de peticiones permitidas | 50 |
| X-RateLimit-Remaining | Peticiones restantes en la ventana actual | 47 |
| X-RateLimit-Reset | Timestamp Unix cuando se resetea el contador | 1738598400 |
Ejemplo de Headers
HTTP/1.1 200 OK
X-RateLimit-Limit: 50
X-RateLimit-Remaining: 47
X-RateLimit-Reset: 1738598400
Content-Type: application/json
Manejo de Errores
Error 429: Too Many Requests
Cuando excedes un límite (individual o global), recibes:
HTTP/1.1 429 Too Many Requests
Retry-After: 42
X-RateLimit-Limit: 50
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1738598442
Content-Type: application/json
{
"error": "Demasiadas peticiones. Por favor, intenta de nuevo más tarde.",
"retry_after": "42 seconds"
}
Headers importantes:
- Retry-After: Segundos que debes esperar antes de reintentar
- X-RateLimit-Reset: Timestamp exacto cuando se resetea tu cuota
¿Límite Individual o Global?
El error 429 puede ocurrir por dos razones:
1. Límite individual alcanzado: Solo tú has excedido tu límite de 200/hora o 50/min
- Otros usuarios no se ven afectados
- Espera el tiempo indicado en Retry-After y reintenta
2. Límite global alcanzado: El servidor está sobrecargado (5000/hora o 1000/min total)
- Todos los usuarios están siendo limitados
- Espera más tiempo antes de reintentar (puede haber congestión)
- Considera contactar soporte si ocurre frecuentemente
Identificación de Clientes
El sistema identifica a los clientes de dos formas:
1. Por Usuario Autenticado (Preferido)
Si envías un token JWT válido:
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
El límite se aplica por: sub (subject) del JWT
Ventajas:
- ✅ Múltiples IPs pueden compartir el mismo usuario
- ✅ Límites personalizables por usuario
- ✅ Auditoría completa
2. Por Dirección IP (Fallback)
Si no hay JWT o el JWT es inválido:
El límite se aplica por: Dirección IP del cliente
Consideraciones:
- ⚠️ Puede afectar a múltiples usuarios detrás de un NAT
- ⚠️ No permite auditoría detallada
Buenas Prácticas
✅ Monitorea los Headers
Siempre revisa los headers X-RateLimit-* en tus respuestas:
import requests
response = requests.get(
'https://api.imaginaenergia.com/contratos',
headers={'Authorization': f'Bearer {token}'}
)
remaining = int(response.headers.get('X-RateLimit-Remaining', 0))
if remaining < 10:
print(f"⚠️ Solo quedan {remaining} peticiones")
✅ Implementa Exponential Backoff
Cuando recibas un 429, espera antes de reintentar:
import time
import requests
def hacer_peticion_con_retry(url, headers, max_retries=3):
for intento in range(max_retries):
response = requests.get(url, headers=headers)
if response.status_code == 429:
retry_after = int(response.headers.get('Retry-After', 60))
print(f"⏳ Rate limit alcanzado. Esperando {retry_after}s...")
time.sleep(retry_after)
continue
return response
raise Exception("Máximo de reintentos alcanzado")
✅ Cachea Resultados
Evita peticiones innecesarias cacheando datos que no cambian frecuentemente:
import time
class TarifasCache:
def __init__(self):
self.cache = None
self.timestamp = 0
self.ttl = 3600 # 1 hora
def get_tarifas(self, api_client):
now = time.time()
if self.cache is None or (now - self.timestamp) > self.ttl:
self.cache = api_client.get_tarifas()
self.timestamp = now
return self.cache
❌ Evita Polling Agresivo
No hagas polling cada segundo. Usa intervalos razonables:
# ❌ Mal: 60 peticiones por minuto
while True:
estado = api.get_contrato_estado(id)
time.sleep(1)
# ✅ Bien: 2 peticiones por minuto
while True:
estado = api.get_contrato_estado(id)
if estado == 'completado':
break
time.sleep(30) # 30 segundos
✅ Usa Webhooks en Lugar de Polling
Para operaciones asíncronas, usa callbacks:
# ✅ Mejor: Sin polling, usas callbacks
response = api.crear_contrato(
datos=datos_contrato,
callback_url='https://tuservidor.com/webhook/contrato'
)
# Tu servidor recibirá la notificación cuando esté listo
Ejemplos de Código
Python con Manejo Completo
import requests
import time
from typing import Optional, Dict, Any
class ImaginaEnergiaClient:
def __init__(self, token: str, base_url: str = "https://api.imaginaenergia.com"):
self.token = token
self.base_url = base_url
self.session = requests.Session()
self.session.headers.update({
'Authorization': f'Bearer {token}',
'Content-Type': 'application/json'
})
def _request_with_rate_limit(
self,
method: str,
endpoint: str,
max_retries: int = 3,
**kwargs
) -> requests.Response:
"""Realiza una petición con manejo automático de rate limiting"""
url = f"{self.base_url}{endpoint}"
for intento in range(max_retries):
response = self.session.request(method, url, **kwargs)
# Mostrar info de rate limit
remaining = response.headers.get('X-RateLimit-Remaining')
limit = response.headers.get('X-RateLimit-Limit')
if remaining and limit:
print(f"📊 Rate limit: {remaining}/{limit} peticiones restantes")
# Manejar rate limit
if response.status_code == 429:
retry_after = int(response.headers.get('Retry-After', 60))
print(f"⏳ Rate limit alcanzado. Esperando {retry_after}s...")
time.sleep(retry_after + 1) # +1 segundo de margen
continue
# Manejar otros errores
response.raise_for_status()
return response
raise Exception(f"Máximo de reintentos ({max_retries}) alcanzado")
def get_contratos(self, pagina: int = 1, por_pagina: int = 20) -> Dict[Any, Any]:
"""Obtiene listado de contratos"""
response = self._request_with_rate_limit(
'GET',
'/contratos',
params={'pagina': pagina, 'por_pagina': por_pagina}
)
return response.json()
def crear_contrato(self, datos: Dict[Any, Any]) -> Dict[Any, Any]:
"""Crea un nuevo contrato"""
response = self._request_with_rate_limit(
'POST',
'/contrato/residencial/c1',
json=datos
)
return response.json()
# Uso
client = ImaginaEnergiaClient(token='tu_token_jwt')
try:
contratos = client.get_contratos(pagina=1)
print(f"✅ Contratos obtenidos: {len(contratos)}")
except Exception as e:
print(f"❌ Error: {e}")
JavaScript con Axios
const axios = require('axios');
class ImaginaEnergiaClient {
constructor(token, baseURL = 'https://api.imaginaenergia.com') {
this.client = axios.create({
baseURL,
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
}
});
// Interceptor para manejar rate limiting
this.client.interceptors.response.use(
response => {
// Mostrar info de rate limit
const remaining = response.headers['x-ratelimit-remaining'];
const limit = response.headers['x-ratelimit-limit'];
if (remaining && limit) {
console.log(`📊 Rate limit: ${remaining}/${limit} peticiones restantes`);
}
return response;
},
async error => {
if (error.response && error.response.status === 429) {
const retryAfter = parseInt(error.response.headers['retry-after'] || 60);
console.log(`⏳ Rate limit alcanzado. Esperando ${retryAfter}s...`);
await new Promise(resolve => setTimeout(resolve, (retryAfter + 1) * 1000));
// Reintentar la petición
return this.client.request(error.config);
}
return Promise.reject(error);
}
);
}
async getContratos(pagina = 1, porPagina = 20) {
const response = await this.client.get('/contratos', {
params: { pagina, por_pagina: porPagina }
});
return response.data;
}
async crearContrato(datos) {
const response = await this.client.post('/contrato/residencial/c1', datos);
return response.data;
}
}
// Uso
const client = new ImaginaEnergiaClient('tu_token_jwt');
(async () => {
try {
const contratos = await client.getContratos(1);
console.log(`✅ Contratos obtenidos: ${contratos.length}`);
} catch (error) {
console.error(`❌ Error: ${error.message}`);
}
})();
Incremento de Límites
Si necesitas límites más altos para tu caso de uso:
Requisitos
- Justificación técnica: Describe por qué necesitas más peticiones
- Plan de uso: Explica cómo usarás la API
- Medidas de caché: Qué estás haciendo para minimizar peticiones
Proceso
- Contacta con: serviciosistemas@imaginaenergia.com
- Incluye tu client_id o email de autenticación
- Proporciona los detalles arriba mencionados
Respuesta
- ⏱️ Tiempo de respuesta: 2-5 días laborables
- 📊 Evaluaremos tu caso de uso
- ✅ Si se aprueba, ajustaremos los límites de tu cuenta
FAQ
¿Los límites se comparten entre diferentes endpoints?
No. Cada límite es independiente por categoría de endpoint.
¿Qué pasa si tengo múltiples servicios usando el mismo token?
Los límites se suman. Si tienes 3 servicios usando el mismo token, todos comparten la misma cuota.
Recomendación: Usa tokens diferentes para cada servicio si es posible.
¿Los límites se resetean exactamente cada hora?
Sí. El sistema usa ventanas fijas. Si tu primera petición es a las 10:15, tu cuota se resetea a las 11:00, no a las 11:15.
¿Puedo ver mi uso histórico?
Actualmente no hay un endpoint dedicado, pero estamos trabajando en ello. Entre tanto, puedes trackear tu uso guardando los headers X-RateLimit-* de cada respuesta.
¿Qué pasa si envío peticiones desde diferentes IPs pero con el mismo JWT?
El límite se aplica por JWT sub, no por IP. Todas tus peticiones comparten la misma cuota independientemente de la IP.
¿Por qué recibo error 429 si no he hecho muchas peticiones?
Puede ser por dos razones:
- Tus peticiones previas: Recuerda que los límites son por hora/minuto. Si hiciste muchas peticiones hace 30 minutos, aún cuentan para tu cuota.
- Límite global alcanzado: Otros usuarios han saturado el servidor. El límite global (5000/hora o 1000/min) protege el servidor de sobrecarga total. Cuando se alcanza, todos los usuarios son limitados temporalmente.
Solución: Espera el tiempo indicado en Retry-After. Si ocurre frecuentemente, contacta a soporte.
¿Cómo sé si me limitaron por mi uso o por el límite global?
Si estás bien dentro de tu límite individual (ej: 10 peticiones vs límite de 50/min) pero recibes 429, probablemente se alcanzó el límite global. Desafortunadamente, los headers no distinguen entre ambos casos actualmente.
¿Los límites globales se pueden incrementar?
Los límites globales están configurados para el hardware actual del servidor. Si necesitas más capacidad para tu organización, contacta a soporte para explorar soluciones dedicadas o planes enterprise.
Documentación Adicional
Si eres administrador del sistema y necesitas configurar o ajustar los límites de rate limiting, consulta la Guía de Configuración de Rate Limiting que incluye:
- Variables de entorno y configuración
- Guías de dimensionamiento por tamaño de servidor
- Configuración de Redis para producción
- Monitorización y troubleshooting
Soporte
Si tienes dudas o problemas relacionados con rate limiting:
📧 Email: serviciosistemas@imaginaenergia.com
📚 Documentación: Índice de documentación
Última actualización: 10 de Febrero, 2026 | Versión: 1.0