Factuarea APIDevelopers

Límites de peticiones

Cuotas por clave, empresa y cartera de la cuenta según el tier. Cabeceras X-RateLimit-* y back-off recomendado.

La API pública evalúa tres ejes de cuota para garantizar la equidad entre tenants y proteger el backend frente a picos:

  1. API key — ventana deslizante por minuto y volumen mensual.
  2. Empresa — el agregado de todas las claves de la empresa.
  3. Cartera de la cuenta — la cuenta a la que pertenece la credencial, solo cuando esa cuenta tiene dos o más NIF reales.

Los límites dependen del tier de tu API key. El tier se deriva del plan de tu cuenta: nunca se fija por clave ni por petición, no existe una compra de capacidad independiente y se actualiza automáticamente cuando cambia el plan. Solo las migraciones históricas grandfathered_addon pueden conservar un tier superior, y únicamente mientras siga activo un plan válido.

Niveles

TierClave/minClave/mesEmpresa/minEmpresa/mesIncluido con
Free1010010100El trial de 10 días.
Starter305.0009015.000El plan Esencial.
Pro30050.000900150.000Los planes Profesional y Avanzado.
ScaleSegún contratoSegún contratoSegún contratoSegún contratoEl plan Enterprise.

Los límites por clave se aplican. Los agregados por empresa están presentes en el contrato y, en la versión entrante de la aplicación, funcionan en modo de observación (shadow): miden los rechazos que habrían ocurrido sin devolver 429. No trates ese modo como capacidad contratada; puede promocionarse a aplicación efectiva después de calibrarlo sin cambiar la forma de la petición ni de la respuesta.

Las claves fact_test_ siguen consumiendo su cuota por clave, pero los ejes agregados de empresa y cartera omiten las empresas sandbox para que el tráfico de prueba no consuma capacidad agregada de producción.

Ventana deslizante

El cubo por minuto no es una ventana fija de "60 segundos desde las 12:00". Es una ventana deslizante: en cualquier momento, la API cuenta cuántas peticiones aceptadas hay en los últimos 60 segundos para tu clave. Cuando el contador iguala al límite, las peticiones siguientes responden 429 hasta que pase suficiente tiempo para que las primeras peticiones "salgan" de la ventana.

Por qué: no hay un "minuto de gracia" cada 60 segundos en el que pudieras enviar el doble del límite. Más justo y más estable bajo tráfico real.

Techos de empresa y cartera

Cuando los ejes agregados están en aplicación efectiva, la API evalúa primero la clave, y los techos por minuto antes que los mensuales. Un rechazo de empresa usa company_rate_limit_exceeded o company_monthly_quota_exceeded: añadir claves no eleva esos techos porque se cuentan todas juntas.

La cartera de la cuenta

El tercer eje es de la cuenta de la credencial, no del NIF que nombra una petición. Una credencial opera una cartera cuando su propia cuenta tiene al menos dos NIF reales. La sandbox de la cuenta no cuenta, así que un NIF titular y su sandbox no son una cartera, y los NIF archivados tampoco cuentan. Con un solo NIF real este eje nunca se aplica: las peticiones siguen los techos de clave y de empresa de arriba y nada más.

Dos reglas deciden dónde cuenta una petición:

  • Un NIF alcanzado por una relación cuenta en tu cartera. Una petición sobre un NIF que otra cuenta pone a tu alcance, por un acceso cedido o por una cuenta gestionada, suma en la cartera de la cuenta de tu credencial y en el suelo reservado del NIF que nombra. Nunca suma en la cartera de la cuenta dueña de ese NIF.
  • Un NIF que sale de la cuenta cambia de techo. Cuando un NIF pasa a otra cuenta por un traspaso de NIF, las peticiones sobre él dejan de contar en la cartera de la cuenta que abandona y cuentan en la cartera de su cuenta nueva, a través de las credenciales de esa cuenta. Que una cuenta opere o no una cartera se recuerda durante cerca de un minuto, así que un cambio en el número de NIF de una cuenta llega a los techos dentro de ese minuto.

Una cartera tiene un catálogo plano independiente por tier:

TierBanda común/minSuelo reservado por NIF/minCartera/mesClaves activas en la cuenta
Free10101001
Starter18020150.00015
Pro1.800301.500.000500
ScaleSegún contratoSegún contratoSegún contratoSegún contrato

El suelo reservado de un NIF se evalúa primero. Un NIF por debajo de su suelo puede seguir aunque la banda común se haya agotado; la banda común no es, por tanto, un total absoluto de la cartera. La cuota mensual no tiene suelo y agrega toda la cartera. Ninguno de los cuatro valores depende de cuántos NIF tenga la cuenta.

Los techos de cartera por minuto y mensual todavía no están en vigor: funcionan ahora en modo de observación (shadow), pendientes de calibración con tráfico real de cierre. Miden los rechazos que habrían producido sin devolver 429, y mientras solo observan, el techo por clave sigue aplicándose como antes.

El tope de claves funciona distinto: se comprueba al crear una clave, no en cada petición, y ya está en vigor. Se aplica a una cartera, porque una cuenta con un solo NIF solo se topa con el tope por empresa, y va además de ese tope, que se comprueba primero. Cuenta todas las credenciales de la cuenta que no se han revocado, incluidas las claves de pruebas. Una clave caducada que nadie revocó sigue ocupando su plaza, así que revoca las claves que ya no uses. Una cuenta que ya supera el tope conserva todas sus claves: solo se rechazan las nuevas.

Los rechazos de cartera usan portfolio_rate_limit_exceeded y portfolio_monthly_quota_exceeded, y una clave creada por encima del tope responde 422 portfolio_max_api_keys_exceeded. Dar de alta más NIF o API keys no eleva un techo plano de cartera; reparte el trabajo en el tiempo o solicita una ampliación auditada para la empresa.

Cabeceras de respuesta

Toda respuesta (incluido 429) incluye:

CabeceraSignificado
X-RateLimit-LimitLímite por minuto de tu tier.
X-RateLimit-RemainingPeticiones restantes en la ventana actual.
X-RateLimit-ResetTimestamp UNIX en el que se libera un hueco (una petición sale de la ventana).
Retry-AfterSolo en 429, y nunca en los tres errores de cuota mensual. Segundos hasta que puedas reintentar. Un contador mensual se renueva al empezar el siguiente mes natural.

Ejemplo de cabeceras en una respuesta 200:

HTTP/1.1 200 OK
X-RateLimit-Limit: 300
X-RateLimit-Remaining: 287
X-RateLimit-Reset: 1747314060

Y en un 429 por minuto:

HTTP/1.1 429 Too Many Requests
Retry-After: 7
X-RateLimit-Limit: 30
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1747314007

Código de error

{
  "error": {
    "type": "rate_limit_error",
    "code": "rate_limit_exceeded",
    "message": "Has superado el límite de peticiones. Vuelve a intentarlo en unos segundos.",
    "request_id": "req_..."
  }
}

El code estable identifica qué eje aplicado se ha agotado:

EjePor minutoPor mes
API keyrate_limit_exceededmonthly_quota_exceeded
Empresacompany_rate_limit_exceededcompany_monthly_quota_exceeded
Cartera de la cuentaportfolio_rate_limit_exceededportfolio_monthly_quota_exceeded

Todos usan type: rate_limit_error. Respeta Retry-After en los de por minuto. Los mensuales no llevan Retry-After: el contador se renueva al empezar el siguiente mes natural, así que esperar unos segundos no los resuelve. Los fallos de autenticación repetidos se limitan por separado con code: too_many_auth_failures.

Buenas prácticas

1. Respeta Retry-After

import time, requests

def call_with_retry(url, **kwargs):
    while True:
        resp = requests.get(url, **kwargs)
        if resp.status_code != 429:
            return resp
        sleep = int(resp.headers.get('Retry-After', 1))
        time.sleep(sleep)

Los tres errores de cuota mensual no llevan Retry-After. Un 429 mensual no se resuelve esperando unos segundos: deja de reintentarlo y ramifica según error.code.

2. Back-off exponencial con jitter

Para 5xx, donde no hay Retry-After:

import random, time

def backoff(attempt):
    return min(60, (2 ** attempt) * 0.1 + random.uniform(0, 0.5))

for attempt in range(5):
    resp = requests.get(url)
    if resp.status_code < 500:
        break
    time.sleep(backoff(attempt))

3. Monitoriza X-RateLimit-Remaining

Si tu integración se acerca de forma consistente al 10% del límite, considera:

  • Cambiar a un plan con un tier superior.
  • Agrupar en lotes: en lugar de N POSTs, agrega y haz 1 POST.
  • Cachear lecturas frecuentes (productos, impuestos, series).
  • Suscribirte a webhooks en lugar de hacer polling.

4. Webhooks > polling

Si haces polling de /v1/companies/{company}/invoices?status=paid cada minuto para detectar pagos consumes 30 rpm solo para eso. Suscríbete al evento invoice.paid y reduce eso a 0 peticiones.

5. Claves por integración

Si tienes dos integraciones (un dashboard interno + un cron de exportación), crea dos claves distintas: cada clave tiene sus propios cubos por minuto y mensual, así un cron pesado no consume el cubo de la clave del dashboard.

Separar claves no aumenta la capacidad agregada. Los techos de empresa y cartera suman las claves que correspondan; usa más claves para aislamiento y atribución, no para esquivar la cuota.

Cuotas administrativas

Algunas cargas tienen presupuestos de protección independientes de la tasa de peticiones. No consumen los cubos de clave/empresa/cartera ni aparecen en X-RateLimit-*:

CargaCode estableQué se mide
Envíos de emailemail_recipient_budget_exceededDestinatarios distintos en la ventana, sumados entre credenciales.
Entrega de emailemail_delivery_circuit_openCorte temporal de seguridad del proveedor/empresa tras fallos de entrega; no es una cuota.
Cuentas nuevasaccount_probation_limit_exceededCapacidad reducida por antigüedad hasta que la cuenta madura, verifica su censo AEAT o activa una suscripción de pago.
Endpoints PDFpdf_generation_budget_exceededTrabajo de render horario, por empresa o documento (subcode).
Importaciones y subidasupload_in_flight_budget_exceededBytes temporales cruzando el disco a la vez, no almacenamiento ocupado.
Exportaciones empaquetadasexport_budget_exceededDocumentos empaquetados o artefactos generados por hora (subcode).

Estos codes responden 429 con type: rate_limit_error; usa Retry-After o error.details.retry_at cuando existan. Cambiar de credencial no evita un presupuesto de empresa. Un 402 storage_quota_exceeded distinto indica que la cuenta ha alcanzado su uso máximo; no se libera esperando: escribe a soporte. Los topes de cantidad de endpoints webhook son capacidad del plan, no un presupuesto 429; consulta Precios.

Subida de tier

Cambiar de tier no requiere rotar claves. Cuando tu plan cambia:

  1. Las nuevas cuotas aplican de inmediato.
  2. La cuota mensual consumida en el tier anterior no se reinicia: solo crece el tope mensual.
  3. Las claves existentes conservan su id; el nuevo tier se aplica a todas automáticamente.

Identidad para enviar documentos

El envío de documentos puede requerir identidad acreditada mediante una suscripción activa o una identificación censal aceptada. Un NIF que no es el titular la toma del NIF titular de su cuenta, y los NIF de una cuenta gestionada la toman del NIF titular de la cuenta del proveedor mientras dure la gestión. 422 sender_identity_not_verified requiere corregir esa identidad; un 429 corresponde a un presupuesto de envío distinto. Consulta envío de documentos y la identidad de envío de un NIF.

En esta página

¿Te echamos una mano?Contactar con soporte