Conceptos
Límites de tasa y cuotas
El límite por minuto y la cuota mensual de cada llave, las cabeceras RateLimit-*, qué hacer ante un 429 y los límites de tamaño de las peticiones.
En esta página
Cada llave tiene dos límites, configurados al emitirla:
| Límite | Valor por defecto | Al superarlo |
|---|---|---|
| Por minuto | 120 peticiones por minuto | 429 con Retry-After hasta que se libere la ventana |
| Cuota mensual (opcional) | Sin cuota, salvo que tu contrato la fije | Avisos al cruzar umbrales y, según el contrato, 429 hasta el siguiente período |
Si tu volumen necesita más, pídelo en el onboarding o a soporte: el límite se ajusta por llave.
Cabeceras #
Las respuestas informan el estado de tu ventana actual:
RateLimit-Limit: 120
RateLimit-Remaining: 87
RateLimit-Reset: 23
RateLimit-Policy: 120;w=60| Cabecera | Significado |
|---|---|
RateLimit-Limit | Peticiones permitidas en la ventana. |
RateLimit-Remaining | Cuántas te quedan. |
RateLimit-Reset | Segundos hasta que la ventana se reinicia. |
RateLimit-Policy | Política aplicada (cupo y ventana w= en segundos). |
Retry-After | Solo en 429: segundos a esperar antes de reintentar. |
Un 429 llega como problem+json con type: https://errors.compense.co/gateway/rate-limited.
Cómo responder a un 429 #
Los SDK reintentan los 429 de las lecturas (y de las escrituras si activaste retry_writes)
respetando Retry-After (Reintentos). Si se agotan los intentos,
recibes la excepción con el tiempo de espera:
import time
from compense_gateway import RateLimitError
try:
page = client.credits.list_applications(status="RECEIVED")
except RateLimitError as e:
time.sleep(e.retry_after or 60) # o reencola el trabajoimport { RateLimitError } from "@compense/sdk";
try {
await client.credits.listApplications({ status: "RECEIVED" });
} catch (err) {
if (!(err instanceof RateLimitError)) throw err;
await new Promise((r) => setTimeout(r, (err.retryAfter ?? 60) * 1000)); // retryAfter en segundos
}use Compense\Sdk\Exception\RateLimitException;
try {
$client->credits->listApplications(status: 'RECEIVED');
} catch (RateLimitException $e) {
sleep((int) ceil($e->retryAfter ?? 60));
}try
{
await client.Credits.ListApplicationsAsync(status: "RECEIVED");
}
catch (RateLimitException e)
{
await Task.Delay(e.RetryAfter ?? TimeSpan.FromSeconds(60));
}_, err := client.Credits.ListApplications(ctx, &compense.ListApplicationsParams{Status: "RECEIVED"})
if compense.IsRateLimited(err) {
var apiErr *compense.APIError
errors.As(err, &apiErr)
wait := time.Minute
if apiErr.RetryAfter != nil {
wait = *apiErr.RetryAfter
}
time.Sleep(wait)
}curl -s -D - -o /dev/null "https://sandbox.dev.compense.co/gw/v1/gateway/credits/applications/?status=RECEIVED" \
-H "X-API-Key: $COMPENSE_API_KEY" | grep -iE '^(ratelimit|retry-after)'Diseña para no llegar al límite #
- Procesos masivos por lotes. Para cargar afiliados usa
affiliates.cross(hasta 1.000 por petición) o la carga por archivo, no una llamada por afiliado. - Webhooks en lugar de sondeo. No consultes el estado de una operación en bucle: suscríbete al evento (Webhooks).
- Concurrencia acotada. Limita los trabajadores que llaman al gateway a la vez y usa una cola con reintentos diferidos.
- Caché de lecturas estables (catálogo de facturadores, operadores de recarga, catálogo de salud): cambian poco, no los pidas en cada transacción.
Límites de tamaño #
| Qué | Límite | Al superarlo |
|---|---|---|
| Cuerpo de una petición JSON | 1 MB | 413 |
Archivo de afiliados (multipart/form-data) | 25 MB | 413 |
Lote de affiliates.cross | 1.000 registros por petición | 422 |
page_size / limit | 100 | Se recorta a 100 |