Rate Limits
La API tiene límites independientes para proteger la plataforma y garantizar disponibilidad para todas las empresas.
Límites activos
| Tipo | Límite | Ventana | Alcance |
|---|---|---|---|
| Requests generales | 100 req | Por minuto | Por token de empresa |
| Creación de guías | 500 guías (configurable) | Por día (medianoche Guatemala, UTC-6) | Por empresa |
Límite general (100 req/min)
Aplica a todos los endpoints. Se mide en ventanas deslizantes de 60 segundos por token. Al alcanzar el límite, todos los requests subsecuentes reciben 429 hasta que la ventana se renueve.
Límite diario de guías (500/día por defecto)
Aplica exclusivamente a la creación de guías:
POST /api/v1/guias→ consume 1 del límite diarioPOST /api/v1/guias/batchcon 20 guías → consume 20 del límite diario
El contador se reinicia a medianoche hora Guatemala (UTC-6). Si envías un lote que superaría el límite (quedan 10, envías 20), el lote completo es rechazado y ninguna guía se crea.
El límite diario es configurable por cuenta. Si tu operación requiere más de 500 guías por día, contacta al equipo TPC para ajustar el límite de tu empresa.
Headers de diagnóstico
Cada respuesta incluye el estado del rate limit:
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 87
X-RateLimit-Reset: 1751824200| Header | Descripción |
|---|---|
X-RateLimit-Limit | Límite máximo en la ventana actual |
X-RateLimit-Remaining | Requests restantes antes de ser limitado |
X-RateLimit-Reset | Unix timestamp (segundos) cuando se resetea el contador |
Estos headers son informativos y siguen el estándar de la industria (IETF draft-ietf-httpapi-ratelimit-headers). Son seguros para mostrar a tus clientes y útiles para implementar lógica de reintentos automáticos.
Respuesta 429
{
"success": false,
"error": {
"message": "Rate limit excedido. Intenta en un minuto.",
"code": "RATE_LIMIT_EXCEEDED"
}
}Para el límite diario de guías:
{
"success": false,
"error": {
"message": "Límite diario de guías alcanzado (500/día). Reinicia mañana.",
"code": "DAILY_GUIDE_LIMIT"
}
}Manejo recomendado de 429
async function apiRequest(url, options, retries = 3) {
const res = await fetch(url, options)
if (res.status === 429) {
const resetAt = parseInt(res.headers.get('X-RateLimit-Reset') ?? '0')
const waitMs = Math.max((resetAt * 1000) - Date.now() + 500, 1000)
if (retries > 0) {
await new Promise(r => setTimeout(r, waitMs))
return apiRequest(url, options, retries - 1)
}
}
return res
}Para el límite diario (DAILY_GUIDE_LIMIT), no tiene sentido reintentar — el límite se reinicia a medianoche hora Guatemala (UTC-6), no en minutos.
Créditos y billing
Además de los rate limits de requests, la creación de guías requiere créditos disponibles. Si tu empresa no tiene créditos, recibirás 402 PAYMENT_REQUIRED:
{
"success": false,
"error": {
"message": "Sin créditos disponibles. Adquiere más créditos en el portal.",
"code": "PAYMENT_REQUIRED"
}
}Los créditos se gestionan en el portal de clientes. Las empresas con plan personalizado (APROBADA) no consumen créditos de paquete.
| Condición | Resultado |
|---|---|
Empresa APROBADA | No consume créditos — acceso libre |
| Plan activo con créditos disponibles | Consume 1 crédito por guía |
| Sin plan o créditos agotados | 402 PAYMENT_REQUIRED |
Estrategias para lotes grandes
Para importar volúmenes altos de guías eficientemente:
// Divide en lotes de 50 y despacha respetando el rate limit
async function crearGuiasMasivas(guias) {
const lotes = []
for (let i = 0; i < guias.length; i += 50) {
lotes.push(guias.slice(i, i + 50))
}
const resultados = []
for (const lote of lotes) {
const res = await fetch('https://api.tpcxpress.com/api/v1/guias/batch', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.TPC_API_TOKEN}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ guias: lote }),
})
const { data } = await res.json()
resultados.push(...data.guias)
// Pequeña pausa entre lotes para no saturar el rate limit
if (lotes.indexOf(lote) < lotes.length - 1) {
await new Promise(r => setTimeout(r, 700))
}
}
return resultados
}