Límites de uso
Cada llave de API puede hacer 120 solicitudes por minuto y 10,000 por día por defecto. Los límites son por llave, no por dirección IP, así que las integraciones que comparten IPs (Zapier, Make, n8n) nunca se frenan entre sí.
La API de SpaceKru (v1.1) es una API REST/JSON disponible en todos los planes de pago de SpaceKru. Sincroniza leads en ambos sentidos (upsert por external_id), añade leads a campañas, crea y mueve deals y pide seguimientos a los Empleados de IA, gestiona productos, cotizaciones, órdenes, pagos y reservas, permite que tu plataforma converse con tu Empleado de IA de Customer Service y envía webhooks firmados para 16 eventos que dicen quién causó cada cambio. URL base: https://app.spacekru.com/api/public/v1. Autenticación: llave de API Bearer (sk_live_…). Documentación: https://www.spacekru.com/es/developers. OpenAPI 3.1: https://app.spacekru.com/api/public/v1/openapi.json.
Los límites
| Límite | Por defecto | Ventana |
|---|---|---|
| Solicitudes por llave por minuto | 120 | Ventanas fijas de un minuto (por reloj, UTC). |
| Solicitudes por llave por día | 10,000 | Día calendario en UTC. Se reinicia a las 00:00 UTC. |
| Respuestas de IA en curso | 4 por servidor | Su propio pool: una ráfaga de conversaciones nunca bloquea el resto de la API. |
| Tamaño del body | 1 MB | Por solicitud. Bodies más grandes responden 413 PAYLOAD_TOO_LARGE. |
| Tamaño de página | 100 registros | Por solicitud de lista (por defecto 25). |
| Leads por inscripción | 100 | POST /campaigns/{id}/leads |
¿Necesitas más? Usa más de una llave solo cuando las integraciones sean realmente distintas, y cuéntanos tu caso por la página de contacto.
Headers de límites
Cada respuesta autenticada te dice cómo vas:
| Header | Significado |
|---|---|
X-RateLimit-Limit | Solicitudes permitidas por minuto para esta llave. |
X-RateLimit-Remaining | Solicitudes que quedan en el minuto actual. |
X-RateLimit-Reset | Segundos hasta que se reinicie el minuto actual (una duración, no una marca de tiempo). |
X-RateLimit-Daily-Limit | Solicitudes permitidas por día UTC. |
X-RateLimit-Daily-Remaining | Solicitudes que quedan hoy. |
Retry-After | Segundos que debes esperar. Llega con 429 y 503. |
X-Request-Id | Id de la solicitud. Menciónalo cuando contactes a soporte. |
Content-Language | Idioma de error.message (en o es). |
HTTP/1.1 200 OK
X-RateLimit-Limit: 120
X-RateLimit-Remaining: 117
X-RateLimit-Reset: 41
X-RateLimit-Daily-Limit: 10000
X-RateLimit-Daily-Remaining: 9988
X-Request-Id: 5f2c9a1b7e3dCuando llegas a un límite: 429
- Por encima del límite por minuto:
429 RATE_LIMITEDconRetry-After= segundos hasta el siguiente minuto (máximo 60). - Por encima del límite diario:
429 RATE_LIMITEDconRetry-After= segundos hasta las 00:00 UTC. - Las solicitudes rechazadas por el límite por minuto no cuentan en el límite diario.
Cuando estamos ocupados: 503
503 SERVICE_BUSY: el servidor está atendiendo su máximo de solicitudes en este momento.Retry-After: 5(15para respuestas de conversaciones con IA). Protege a los Empleados de IA de todos los clientes, que corren en los mismos servidores.503 ELIGIBILITY_UNAVAILABLE: no pudimos verificar tu plan por un momento.Retry-After: 10.- Ambos son temporales y se pueden reintentar con seguridad. Las escrituras que fallaron con
503no se aplicaron.
Reintenta con backoff
Reintenta 429 y 503 después de Retry-After segundos más un poco de espera aleatoria, para que muchos procesos no reintenten en el mismo instante. En las creaciones envía una Idempotency-Key para que un reintento nunca cree un duplicado (Idempotencia).
const BASE = 'https://app.spacekru.com/api/public/v1';
// Retries 429 and 503 after Retry-After (+ jitter). Gives up on long waits
// (the daily limit resets at 00:00 UTC) and after 5 retries.
export async function spacekru(path, options = {}, attempt = 0) {
const res = await fetch(`${BASE}${path}`, {
...options,
headers: {
Authorization: `Bearer ${process.env.SPACEKRU_API_KEY}`,
'Content-Type': 'application/json',
...options.headers,
},
});
if ((res.status === 429 || res.status === 503) && attempt < 5) {
const retryAfter = Number(res.headers.get('Retry-After')) || 2 ** attempt;
if (retryAfter > 60) throw new Error('Daily limit reached: resume after 00:00 UTC.');
const waitMs = retryAfter * 1000 + Math.random() * 1000;
await new Promise((resolve) => setTimeout(resolve, waitMs));
return spacekru(path, options, attempt + 1);
}
const body = await res.json();
if (!res.ok) throw new Error(`${body.error.code}: ${body.error.message} (request ${body.error.request_id})`);
return body;
}
// Usage
const page = await spacekru('/leads?limit=100');
console.log(page.data.length);import os
import random
import time
import requests
BASE = "https://app.spacekru.com/api/public/v1"
HEADERS = {"Authorization": f"Bearer {os.environ['SPACEKRU_API_KEY']}"}
def spacekru(method, path, **kwargs):
"""Retries 429 and 503 after Retry-After (+ jitter), at most 5 times."""
for attempt in range(6):
r = requests.request(method, BASE + path, headers=HEADERS, timeout=30, **kwargs)
if r.status_code in (429, 503) and attempt < 5:
retry_after = int(r.headers.get("Retry-After", 2 ** attempt))
if retry_after > 60:
raise RuntimeError("Daily limit reached: resume after 00:00 UTC.")
time.sleep(retry_after + random.random())
continue
body = r.json()
if not r.ok:
err = body["error"]
raise RuntimeError(f"{err['code']}: {err['message']} (request {err['request_id']})")
return body
page = spacekru("GET", "/leads", params={"limit": 100})
print(len(page["data"]))Cómo mantenerte lejos de los límites
- Usa webhooks en vez de consultar una y otra vez. Una suscripción a
lead.createdreemplaza miles de llamadas aGET /leads(Webhooks). - Sincroniza de forma incremental con
updated_sinceylimit=100en vez de releer todo (Paginación y sincronización). - Reparte las tareas por lotes en el tiempo en vez de lanzarlas todas a la vez.