AlchemyCode API docs

Límites, cuotas e idempotencia

Tres controles distintos: rate limit por llave (peticiones por minuto), cuota mensual por cuenta (unidades consumidas) y límites de payload. Entender cuál aplica evita reintentos inútiles.

Rate limit por llave

El límite se aplica por llave de API, no por IP, para no castigar a clientes detrás de NAT. Usa un token bucket con la tasa del plan y una ráfaga adicional:

Texto
capacidad = rate_limit_rpm + burst
recarga  = rate_limit_rpm / 60 peticiones por segundo

Invitación · Beta: capacidad 70, recarga 1 petición/s
PlanUnidades / mesRate limitEmpresasPrecio
Invitación · Beta tu plan2,00060 rpm + 10 burst5Sin costo (beta)
Starter5,000120 rpm + 20 burst15$1,490 MXN / mes (lista)
Growth25,000300 rpm + 40 burst60$5,900 MXN / mes (lista)
Enterprise100,000900 rpm + 120 burst500Cotización
Durante la beta el límite se aplica por llave según tu plan. Las cabeceras X-RateLimit-* y X-Quota-* se están habilitando por entorno: si no aparecen en una respuesta, no dependas de ellas; usa el 429 y Retry-After como fuente de verdad. El consumo sí se mide desde el primer día.

Cabeceras de límite y cuota

CabeceraDescripción
X-RateLimit-LimitCapacidad del bucket (rpm + burst).
X-RateLimit-RemainingPeticiones disponibles en este momento.
X-RateLimit-ResetSegundos para recuperar la siguiente petición.
Retry-AfterSegundos que debes esperar antes de reintentar (en 429).
X-Quota-LimitUnidades incluidas en el periodo mensual.
X-Quota-UsedUnidades consumidas en el periodo.
X-Quota-RemainingUnidades disponibles antes del corte.
X-Request-IdIdentificador de la petición; úsalo en soporte.
X-Response-TimeTiempo de proceso en milisegundos.
X-API-VersionVersión del contrato (v1).

Cuando superas el rate limit, la respuesta es:

HTTP
HTTP/1.1 429 Too Many Requests
Retry-After: 7
Content-Type: application/problem+json
X-Request-Id: req_b41c8e2a7f093d65

{
  "type": "https://api.434alchemycode.com/docs/errors/rate_limited",
  "title": "Demasiadas peticiones",
  "status": 429,
  "code": "RATE_LIMITED",
  "detail": "Superaste el límite por minuto. Respeta `Retry-After`.",
  "retryable": true,
  "request_id": "req_b41c8e2a7f093d65"
}

Cuota mensual

La cuota se mide en unidades, no en peticiones. Cada servicio declara cuántas consume; el buzón IMSS consume 2 porque sincroniza y descarga evidencias. La API evalúa la cuota antes de encolar el job: si no hay unidades, responde 429 QUOTA_EXCEEDED sin consumir ni crear job.

ServicioKeyUnidadesModo
Constancia SATsat.constancia1Asíncrono
Opinión 32-Dsat.opinion1Asíncrono
Domicilio fiscalsat.domicilio1Asíncrono
Buzón IMSSimss.buzon2Asíncrono
Opinión IMSSimss.opinion1Asíncrono
Opinión Infonavitinfonavit.opinion1Asíncrono
Artículo 69-Bsat.articulo69b1Síncrono
CAPTCHAcaptcha.resolve1Síncrono
  • Corte mensual: el periodo es el mes calendario en UTC; resets_at indica el inicio del siguiente.
  • Sin arrastre: las unidades no usadas no se acumulan al mes siguiente.
  • Errores no cobran: un job fallido no consume unidades; un job exitoso sí, aunque el sentido de la opinión sea negativo.
  • Sandbox también mide: las consultas con ck_test_ consumen cuota (con datos simulados).
  • Sin cargo en beta: las unidades se miden, pero no se genera cobro durante la beta.
HTTP
HTTP/1.1 429 Too Many Requests
Content-Type: application/problem+json

{
  "type": "https://api.434alchemycode.com/docs/errors/quota_exceeded",
  "title": "Cuota mensual agotada",
  "status": 429,
  "code": "QUOTA_EXCEEDED",
  "detail": "Usaste 2000 de 2000 consultas del periodo. La cuota se renueva el 2026-11-01.",
  "retryable": false,
  "request_id": "req_7c1f9a3e5b2d8064",
  "quota": {
    "period_start": "2026-10-01T00:00:00+00:00",
    "period_end": "2026-11-01T00:00:00+00:00",
    "quota": 2000,
    "used": 2000,
    "remaining": 0,
    "percent": 100.0,
    "exceeded": true,
    "resets_at": "2026-11-01T00:00:00+00:00"
  }
}

Consulta tu estado en GET /v1/me (cuota y plan) y el detalle en GET /v1/usage (consumo por servicio, empresa, día y tokens de IA).

Idempotencia

Los seis endpoints asíncronos aceptan el encabezado Idempotency-Key. Sirve para que un reintento de red no cree dos jobs ni cobre dos veces.

Shell
curl -sS -X POST "https://api.434alchemycode.com/v1/sat/constancias" \
  -H "Authorization: Bearer $ALCHEMY_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 6f1c2c7a-3d0e-4a51-9b0e-5c2a7f9d1e44" \
  -d '{"company_id": "9b2f5c1e-7a3d-4f8b-9c21-6d4e8a0b5f17"}' 
SituaciónRespuesta
Primera petición con la clave202 y job nuevo.
Reintento con la misma clave y el mismo cuerpo200 con el job actual (se refresca su estado, no el snapshot del primer 202).
Misma clave, cuerpo distinto409 IDEMPOTENCY_CONFLICT.
Misma clave mientras la petición original sigue en proceso409 IDEMPOTENCY_IN_PROGRESS (reintentar en segundos).
Después de 24 horasLa clave se libera: la misma clave crea un job nuevo.

Usa un UUID v4 por operación de negocio y guárdalo junto con tu registro. No uses la misma clave para consultas distintas ni la reutilices entre empresas.

Tamaño de payload

LímiteValorError
Cuerpo de la petición2 MB413 PAYLOAD_TOO_LARGE
Cada archivo de e.firma10 MB413 PAYLOAD_TOO_LARGE
Lote de RFC (69-B)5,000 RFC422 VALIDATION_ERROR
Imagen de CAPTCHA2 MB en base64413 PAYLOAD_TOO_LARGE
Página de listadoper_page máx. 100422 VALIDATION_ERROR
El middleware sólo puede rechazar por Content-Length. Si tu cliente usa chunked encoding sin longitud, el límite se aplica al leer el cuerpo: envía siempre Content-Length.

Buenas prácticas

  • Respeta Retry-After; no reintentes en paralelo tras un 429.
  • Limita la concurrencia de tu cliente (4–8 en beta) y encola lo que exceda.
  • Mide el consumo con /v1/usage; alerta al 80 % de la cuota.
  • Reutiliza Idempotency-Key por operación de negocio, no por reintento manual.
  • Divide lotes de 69-B en bloques de 1,000–2,000 RFC para controlar latencia y memoria.
  • No uses sandbox para estimar cuota de producción: los datos son simulados, pero las unidades se descuentan.