> For the complete documentation index, see [llms.txt](https://docs.nexus.xyz/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.nexus.xyz/api-reference/es-419/guides/rate-limits.md).

# Límites de solicitudes

Cuánto cuesta una solicitud, qué significan los encabezados de límites de solicitudes, qué presupuestos son independientes entre sí y qué pasa cuando superas cada uno.

El Exchange no mide tu tráfico en solicitudes por segundo. Lo mide en **peso por segundo**. A cada solicitud se le cobra un costo: la mayoría cuesta una unidad y unas pocas cuestan más. Un cliente que regula su ritmo contando solicitudes recibe rechazos mientras su propio contador todavía parece estar bien. Esta es la sorpresa de integración más común con esta API.

Esta página explica el modelo: cuánto cuesta cada cosa, qué presupuestos están separados y cómo leer los encabezados. La definición **normativa** es el contrato OpenAPI, publicado en [`nexus-xyz/nexus-exchange-api`](https://github.com/nexus-xyz/nexus-exchange-api) y servido en `/openapi.json`. La sección "Rate limits" de la descripción de la API define la semántica de los encabezados, y cada operación lleva su propio costo legible por máquina. Cuando esta página y el contrato no coinciden, el contrato tiene razón.

### Cuánto cuesta una solicitud

Tu presupuesto es un **token bucket que se recarga de forma continua a la tasa por segundo de tu nivel**, con una capacidad de exactamente un segundo de tokens. De esa capacidad se derivan dos consecuencias. La tasa sostenida y la ráfaga permitida son el mismo número, así que no hay una reserva de varios segundos que puedas acumular quedándote inactivo. Y `remaining` nunca puede superar a `limit`.

La mayoría de las solicitudes cuestan **1**. Las excepciones:

| Costo                             | Se aplica a                                                                                                                                                                                                            | Por qué                                                                                                                                                                                                                                                                                |
| --------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **5**                             | `GET /account/summary`, `GET /fills`, `GET /orders/history`, `GET /account/portfolio-history`, `GET /positions/pnl`, `GET /account/activity`, `GET /stats/referrals`, y las gemelas `/api/v1` de todas menos la última | Cada una procesa o recorre un búfer grande por cuenta (ejecuciones, historial de órdenes, la serie de tiempo del portafolio, el feed de actividad combinado), se reparte entre las posiciones abiertas o agrega conteos de referidos de toda la plataforma desde el backend de cuentas |
| **`1 + floor(order_count / 40)`** | `POST /orders/batch`                                                                                                                                                                                                   | Hasta 40 órdenes cuestan lo mismo que una; cada 40 adicionales suman una unidad                                                                                                                                                                                                        |
| **1**                             | todas las demás operaciones que documenta el contrato                                                                                                                                                                  | El valor predeterminado                                                                                                                                                                                                                                                                |

Así que quien llama con nivel Pro y `limit: 20` obtiene 20 lecturas de ticker por segundo, **o 4 lecturas de `/fills`**, del mismo presupuesto en el mismo nivel. Regula tu ritmo según el peso, no según la cantidad de solicitudes.

Dos propiedades de seguridad acotan el peor caso. El cobro de una sola solicitud tiene un tope de un segundo de tokens, así que un lote demasiado grande nunca puede volverse permanentemente imposible de pagar. Consume el segundo completo una vez que el bucket se recarga y pasa, en lugar de quedar en un ciclo infinito de reintentos que nunca podría pagar. Y a un cuerpo de lote que el servidor no puede analizar se le cobra la unidad base en lugar de rechazarlo por el cálculo de peso.

En lugar de fijar en el código la tabla de arriba, lee el costo del contrato: las operaciones que cuestan más de una unidad llevan **`x-nexus-rate-limit-weight`**, y las que tienen un costo que depende del cuerpo también llevan **`x-nexus-rate-limit-weight-formula`**. **Para una operación que documenta el contrato, la ausencia del marcador significa peso 1.** Esa es la forma sobre la que hay que construir un limitador del lado del cliente.

La salvedad importa. El contrato enumera las operaciones admitidas, y la regla se cumple en todas ellas, pero no dice nada sobre otras rutas que casualmente respondan. Una ruta que el contrato no enumera no lleva ningún marcador, no está cubierta por la regla y puede cobrarse de forma distinta a lo que sugiere su ausencia. Construye sobre las operaciones que documenta el contrato, no sobre rutas encontradas sondeando. Esas operaciones son las que describen los pesos, y esta página.

### Cuatro presupuestos, no uno

Hay cuatro clases de recursos independientes. Gastar una no gasta las demás, y cada una rechaza a su manera:

| Clase                             | Cubre                                                                             | Se cobra contra                                                                          |
| --------------------------------- | --------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------- |
| **Solicitudes**                   | Todas las operaciones REST que no son escrituras de órdenes                       | Tus buckets de solicitudes por clave y por propietario                                   |
| **Acciones de trading**           | `POST` y `PATCH` bajo `/orders`, marcadas con `x-nexus-rate-limit-class: trading` | Un bucket de órdenes dedicado, del mismo tamaño por segundo que el bucket de solicitudes |
| **Cancelaciones**                 | `DELETE` bajo `/orders`, también marcadas con `x-nexus-rate-limit-class: trading` | Un bucket de cancelaciones **separado**, también del mismo tamaño por segundo            |
| **Plano de control de WebSocket** | Conexiones, suscripciones y frames entrantes del cliente                          | Topes por nivel. Consulta [Topes de WebSocket](#websocket-ceilings)                      |

Una escritura de orden se cobra al bucket de trading **en lugar del** bucket de solicitudes, no además de él. Gracias a esa separación, una ráfaga de polling no puede dejar sin recursos al envío de tus órdenes, y el flujo de órdenes no puede dejar sin recursos a tus lecturas. De ahí se sigue que **un `x-ratelimit-remaining` holgado en tu última lectura no te dice nada sobre tu holgura para enviar órdenes.** Son buckets distintos, así que consulta el bucket del que estás por gastar. `GET /account/rate-limit` informa cada presupuesto por separado en `buckets`, y `buckets.order` responde si puedes enviar una orden.

#### Las cancelaciones nunca comparten un token con los envíos

Cancelar es la única acción que se separa del trading en un presupuesto propio. Un `DELETE` en los endpoints de órdenes (cancelar una, cancelar todas o cancelar por mercado) se cobra al bucket de cancelaciones en lugar del bucket de órdenes, así que **una clave que gastó toda su asignación de envíos enviando órdenes todavía tiene una asignación completa e intacta para retirarlas.**

Esta es la única asimetría deliberada del modelo. Los envíos pueden esperar, y la reducción del riesgo no. Un limitador que rechaza tu cancelación mientras una posición se mueve en tu contra convierte un control de uso justo en una pérdida. Por eso la regla es incondicional. Agotar los envíos nunca puede rechazar una cancelación, porque los dos nunca consumen el mismo token.

Para un cliente, esto significa:

* **Nunca deduzcas tu holgura de cancelaciones a partir de un `429` de envío.** Un bucket `order` vacío no dice nada sobre el `cancel`. Un cliente que aplica backoff a todas las llamadas de órdenes después de un rechazo de envío frenó justo la llamada que todavía debería estar haciendo.
* **Un bucket separado no es una forma de saltarse el límite.** Las cancelaciones se miden a la misma tasa por segundo del nivel que todo lo demás, así que un ciclo de cancelaciones igual puede recibir un `429`. Lleva `bucket: cancel`, el único rechazo que significa que tu canal de cancelaciones está saturado. En ese caso, respeta `retry-after`.

Las modificaciones se cobran como envíos, no como cancelaciones. `PATCH` no indica si una modificación reduce o aumenta la exposición, y una modificación que aumenta el tamaño es un envío se mire como se mire. Así que la garantía de arriba solo se aplica al método que siempre reduce el riesgo. Si necesitas la garantía, cancela.

`POST /orders/preview` también es una acción de trading, algo fácil de pasar por alto. Es una escritura bajo `/orders` y cuesta una unidad de clase trading, igual que enviar una orden. Por eso, previsualizar antes de cada orden reduce a la mitad tu tasa efectiva de envío. Presupuesta dos cobros de clase trading por cada orden enviada de esa forma, u omite la previsualización cuando ya conoces el dimensionamiento.

Quien llama presentando una clave HMAC pasa por un bucket **por clave** y luego por el bucket **por propietario** de su nivel, y el tope efectivo es el que se alcance primero. `GET /account/rate-limit` informa ese mínimo, y consultarlo no tiene costo. Es la única operación que no consume tokens, así que regular tu ritmo no puede frenarte.

Si tu cuenta acaba de subir de nivel, ten en cuenta que el tope propio de una clave se registra cuando se crea la clave (20/s por defecto), y un cambio de nivel no lo reescribe. Por eso, una cuenta Market Maker que todavía usa una clave generada con el valor predeterminado puede quedar limitada al número de la clave y no al del nivel. Lee `/account/rate-limit` después de un cambio de nivel en lugar de suponer la cifra del nivel, y genera una clave nueva si el mínimo informado no es el que esperas.

### Cómo leer los encabezados

* En **todas** las respuestas autenticadas: `x-ratelimit-limit` y `x-ratelimit-remaining`.
* **Solo en un `429`**, además: `x-ratelimit-reset` (segundos Unix) y `retry-after` (segundos, nunca menos de 1).

No esperes los dos últimos en una respuesta exitosa. Un cliente que lee `x-ratelimit-reset` de una 2xx no lee nada.

**`remaining` y `retry-after` usan unidades distintas, a propósito.** `remaining` cuenta solicitudes de costo unitario, así que `x-ratelimit-remaining: 10` significa diez solicitudes de peso 1 *o* dos pesadas. `retry-after` se deriva del costo ponderado de la solicitud rechazada. Un limitador que lee `remaining` como "solicitudes del tipo que estoy por enviar" enviará de más en los endpoints pesados y provocará sus propios 429.

Un rechazo es un `HTTP 429` con este cuerpo:

```json
{
  "code": "RATE_LIMIT_EXCEEDED",
  "message": "Order placement rate limit exceeded",
  "bucket": "order",
  "tier": "Pro"
}
```

Ramifica según `code` y luego según **`bucket`**. Es uno de `key`, `owner`, `order`, `cancel`, `ip` o `login`, y para los cuatro primeros es la clave que hay que buscar en `buckets` de `GET /account/rate-limit`. `ip` y `login` nunca aparecen allí. Ambos miden una conexión y no una cuenta, y `login` se rechaza incluso antes de que exista una cuenta. El mismo valor se envía en el encabezado `x-ratelimit-bucket`, para que un proxy o un wrapper de reintentos pueda leerlo sin analizar el cuerpo. El `message` nombra qué bucket se agotó (`Rate limit exceeded`, `API key rate limit exceeded`, `Order placement rate limit exceeded` o `IP rate limit exceeded`). Es un **diagnóstico**. Su redacción no es estable, así que no lo compares de forma programática.

A diferencia de los rechazos `403` por jurisdicción, un `429` **sí** se puede reintentar: respeta `retry-after` y aplica backoff. Regular tu ritmo según `x-ratelimit-remaining` es mejor que descubrir el tope chocando con él.

El `GET /account/rate-limit` sin costo informa el mismo estado sin gastar un token. Los campos de nivel superior cubren la clase de solicitudes, y `buckets` cubre cada presupuesto:

```json
{
  "tier": "pro",
  "limit": 20,
  "remaining": 17,
  "reset_at_ms": 1750000000123,
  "buckets": {
    "key":    { "limit": 20, "remaining": 17, "reset_at_ms": 1750000000123 },
    "owner":  { "limit": 20, "remaining": 19, "reset_at_ms": 1750000000051 },
    "order":  { "limit": 20, "remaining": 20, "reset_at_ms": 0 },
    "cancel": { "limit": 20, "remaining": 20, "reset_at_ms": 0 }
  }
}
```

**`buckets` se indexa con las mismas etiquetas que usa un `429`**, tanto en su campo `bucket` como en el encabezado `x-ratelimit-bucket`. Así, un rechazo corresponde directamente al estado que lo causó: `buckets[error.bucket]`. Construye tu limitador en torno a esa búsqueda. `key` solo aparece cuando te limita un bucket por clave, y ni `ip` ni `login` aparecen nunca, porque ambos miden una conexión y no una cuenta.

Los `limit`, `remaining` y `reset_at_ms` de nivel superior son la clase de **solicitudes**, sin cambios, así que nada de lo que los lee necesita cambiar. No responden "¿puedo enviar una orden?". Eso lo responde `buckets.order`. En una clave que acaba de cotizar hasta llegar al tope de envíos, los dos no coinciden en absoluto: `remaining: 20` junto con `buckets.order.remaining: 0`.

Dos detalles que hay que manejar cuando usas tanto este endpoint como los encabezados. `reset_at_ms` está en **milisegundos**, mientras que el encabezado `x-ratelimit-reset` está en **segundos** Unix. Y el nombre del nivel está en minúsculas aquí (`pro`) pero no en el cuerpo del `429` (`Pro`), así que compáralo sin distinguir mayúsculas de minúsculas en lugar de contra un literal.

Los tres campos numéricos son `null` para quien llama con nivel `Unlimited`, que se agrupa por IP y no por cuenta. `buckets` vuelve como `{}`, porque ningún presupuesto de alcance de cuenta mide a quien llama con ese nivel.

### Niveles y topes actuales

Los niveles son multiplicadores sobre un mismo modelo, no modelos distintos. **Pro** es el predeterminado para todas las cuentas. **MarketMaker** lo asigna un administrador. Solicítalo a través de tu contacto en Nexus, y consulta la [Guía para market makers](https://docs.nexus.xyz/exchange/apis-and-rates/market-maker-guide). **Unlimited** existe para claves de gateway que multiplexan a muchos usuarios y nunca se asigna a una cuenta de trading.

| Nivel         | Solicitudes  | Acciones de trading                            | Conexiones WS | Suscripciones WS | Frames entrantes WS |
| ------------- | ------------ | ---------------------------------------------- | ------------- | ---------------- | ------------------- |
| `Pro`         | 20/s         | 20/s                                           | 5             | 50               | 10/s                |
| `MarketMaker` | 2,000/s      | 2,000/s                                        | 100           | 1,000            | 50/s                |
| `Unlimited`   | por IP, 50/s | por IP, 50/s, el mismo bucket que las lecturas | exento        | exento           | exento              |

Tres límites se aplican sin importar el nivel, todos antes de que tengas una credencial. Las lecturas de datos de mercado sin autenticación se agrupan **por IP de cliente a 50/s**. `POST /auth/login` se mide por separado y de forma mucho más estricta, a **5/s por IP de cliente** en un bucket propio. Un intento de inicio de sesión cuesta un ecrecover sobre una firma EIP-191, y cualquiera que pueda llegar al endpoint puede hacer que el servidor pague ese costo. El límite no es una defensa contra adivinar el secreto, ya que el mensaje firmado es una constante fija y no hay nada que probar por fuerza bruta. Es una defensa de costos. El tráfico cuya IP de cliente no se puede resolver en absoluto tampoco se admite sin límite. Las lecturas comparten un bucket estricto de 5/s y los inicios de sesión comparten un **segundo bucket, separado**, así que una avalancha que elimina su `x-forwarded-for` no puede agotar el bucket del que depende el resto del tráfico que no se puede resolver. Un origen que no se puede resolver recibe un tope bajo, no la ausencia de tope.

Un rechazo de inicio de sesión lleva `bucket: login`, que es el único rechazo que significa que la propia validación de inicio de sesión está saturada. Es un tope por IP, así que lo compartes con todos los que están detrás de tu NAT o de tu proxy de salida, y no dice nada sobre tu cuenta. Todavía no hay cuenta.

Las cancelaciones tienen su propio presupuesto a la tasa de acciones de trading (otros 20/s para `Pro`, 2,000/s para `MarketMaker`). La tabla no les da una columna propia porque los dos números son iguales por diseño.

`Unlimited` tiene exenciones más acotadas de lo que sugiere su nombre. Sus escrituras de órdenes **y sus cancelaciones** **no** están exentas de los límites de solicitudes. Se saltan tanto el bucket de trading dedicado como el bucket de cancelaciones, y se cobran al mismo bucket por IP que sus lecturas. Así que allí no se cumplen ni la independencia de clases de arriba ni la garantía de cancelación, y el propio polling de un gateway puede desplazar su flujo de órdenes, en el nivel cuya mezcla de tráfico es la menos predecible. Los topes de WS de los que está exento son los *por cuenta*. El tope de conexiones por IP de abajo sigue aplicándose.

**Estos números son los valores predeterminados actuales, no un contrato.** Son configuración del despliegue (algunos todavía son constantes en el código), y cambiarán a medida que se finalice el sistema de niveles. Lee `/account/rate-limit` en lugar de fijarlos en el código.

### Topes de WebSocket

Los topes de WebSocket son una clase de recursos propia, independiente del presupuesto de solicitudes REST y del presupuesto de acciones de trading. Agotar uno no afecta a los demás.

Las **conexiones** tienen un tope por cuenta según el nivel (Pro 5, MarketMaker 100). Un **tope por IP separado, de 5 por defecto,** se aplica primero, en el momento del upgrade, y rige en todos los niveles, incluido `Unlimited`, así que una sola dirección de origen no puede alcanzar por sí sola la cifra por cuenta. Una conexión rechazada ahí recibe un `HTTP 429` (`ws_conn_limit_exceeded`) en la solicitud de upgrade en lugar de un frame de cierre. El token de stream de un solo uso se consume de todos modos, así que genera uno nuevo antes de reconectarte.

Las **suscripciones** tienen el mismo tope dos veces: por conexión *y* entre todas las conexiones de una cuenta. Por eso, abrir más sockets no da más suscripciones. Volver a suscribirte a una clave `(channel, market)` que ya tienes la reemplaza en el lugar y no tiene costo. Superar el tope devuelve un frame `error` (`subscription_limit_exceeded`) en lugar de un código de estado, porque no hay respuestas HTTP una vez que el socket está abierto.

Los **frames entrantes** (tus suscripciones, desuscripciones y pings) están limitados a la tasa sostenida por nivel, con una **ráfaga de 2×** tolerada por encima, así que una tormenta de reconexiones y resuscripciones no se penaliza. Más allá de eso, el servidor **descarta** los frames que superan el límite y envía un aviso `error` por ventana de contabilización en lugar de uno por frame, para que una avalancha entrante no se convierta en una saliente. Una inundación sostenida, es decir, suficientes frames descartados dentro de una ventana, cierra la conexión con el código **`1008`** (violación de política). El servidor no aplica un frame descartado y no te avisa. Si no ves un ack `subscribed`, vuelve a enviar la suscripción después de un backoff en lugar de suponer que se aplicó.

### Los presupuestos son por red

Cada red es un despliegue propio, así que **cada red tiene sus propios buckets**. Gastar en testnet no reduce la holgura de mainnet cuando se lance mainnet, ni al revés. Las credenciales tampoco cruzan de una red a otra. Una clave queda vinculada a la red que la generó. Consulta [Redes](/api-reference/es-419/guides/networks.md).

### Dónde se aplican los límites hoy

Hay una limitación actual que se ve desde afuera, y funciona a tu favor, no en tu contra.

El proceso del gateway mantiene el estado del limitador **en memoria**, no en un almacén compartido. De esto se derivan dos cosas. Primero, no es duradero. Un nuevo despliegue reinicia tus buckets, y una subida de nivel puede volver brevemente al nivel base hasta que se vuelva a aplicar. Segundo, cuando el gateway de una red ejecuta más de una réplica, cada una mantiene sus propios buckets, así que el tope *agregado* que observa un cliente puede ser más alto que la cifra por segundo publicada, según cómo se distribuyan sus conexiones.

No diseñes contando con esa holgura. Trata el número publicado como el tope al que tienes derecho y regula tu ritmo según él. El extra proviene de dónde se aplican actualmente los límites, no se distribuye de forma pareja y desaparecerá cuando los contadores pasen a un almacén compartido. Un cliente construido según la cifra publicada seguirá funcionando cuando eso ocurra. Uno ajustado al agregado observado empezará a ver 429.

### ¿Tu firmador puede seguir el ritmo?

El cliente firma cada solicitud autenticada antes de que salga, así que el firmador impone un tope propio por debajo de los presupuestos de arriba. Revisa ese tope antes de elegir un SDK. Depende mucho más del esquema y de la biblioteca criptográfica que del lenguaje.

El Exchange acepta dos esquemas de firma de solicitudes (consulta [Autenticación](/api-reference/es-419/guides/authentication.md#signing-a-request-with-the-key) y [Agentes](/api-reference/es-419/guides/agent-keys.md)):

* **HMAC** (`hmacAuth`). HMAC-SHA256 sobre la cadena canónica de cinco campos, con el secreto de la API decodificado de hex como clave. Un MAC simétrico toma microsegundos en cualquier lenguaje.
* **Clave de agente** (`agentAuth`). ECDSA secp256k1 sobre el `keccak256` de la cadena canónica de seis campos, con S bajo, enviada como `r||s||v` de 65 bytes. Es una firma de curva elíptica, así que su costo depende de si la biblioteca subyacente es código nativo o código interpretado puro.

Medido a través de la ruta de firma propia de cada SDK, sobre un cuerpo fijo de `POST /api/v1/orders`, en un solo hilo. Es la misma llamada que hace el cliente en cada solicitud, incluida la construcción de la cadena canónica, el hash del cuerpo y la codificación en hex del resultado, pero sin E/S de red:

| SDK                                | Esquema         | Criptografía subyacente              |    p50 |    p95 |    Firmas/s | p50 en 5 corridas |
| ---------------------------------- | --------------- | ------------------------------------ | -----: | -----: | ----------: | ----------------- |
| Rust (`nexus-exchange-rs`)         | HMAC            | `hmac` + `sha2`                      | 0.9 µs | 0.9 µs | \~1,080,000 | 0.88–0.96 µs      |
| Rust (`nexus-exchange-rs`)         | Clave de agente | `k256`                               |  79 µs |  91 µs |    \~12,500 | 74–79 µs          |
| TypeScript (`nexus-exchange-ts`)   | HMAC            | Web Crypto (asíncrono)               |  27 µs |  43 µs |    \~29,000 | 24–35 µs          |
| TypeScript (`nexus-exchange-ts`)   | Clave de agente | `@noble/curves`                      | 319 µs | 470 µs |     \~2,900 | 293–645 µs        |
| Python (`nexus-exchange-py`)       | HMAC            | `hmac` de stdlib                     | 2.1 µs | 2.2 µs |   \~460,000 | 1.96–2.25 µs      |
| Python, instalación predeterminada | Clave de agente | backend Python puro de `eth-keys`    | 3.5 ms | 4.2 ms |       \~280 | 3.43–4.11 ms      |
| Python + `coincurve`               | Clave de agente | libsecp256k1 a través de `coincurve` |  97 µs | 110 µs |    \~10,000 | 96–116 µs         |

La CLI firma a través del crate de Rust, así que hereda las filas de Rust en lugar de tener cifras propias.

**En el nivel `Pro`, ningún SDK ni ningún esquema está limitado por el firmador.** 20 solicitudes por segundo dejan 50 ms por firma. La fila más lenta, la firma con clave de agente en una instalación predeterminada de Python, usa 3.5 ms de eso, así que puede firmar unas catorce veces la tasa Pro en un solo núcleo. Incluso quien llama saturando los tres buckets Pro a la vez (solicitudes, acciones de trading y cancelaciones, 60 solicitudes firmadas por segundo) gasta alrededor de una quinta parte de un núcleo en firmar. El firmador con clave de agente de TypeScript tiene más de cien veces esa holgura, y HMAC es prácticamente gratis en todos los SDK.

**En el nivel `MarketMaker`, el esquema y la biblioteca empiezan a importar.** Sus 2,000 acciones de trading por segundo, más otras 2,000 cancelaciones aparte, dejan 0.25–0.5 ms por firma en un solo hilo.

* **Python con clave de agente:** una instalación predeterminada firma unas 280 por segundo, aproximadamente una séptima parte del tope de trading. Instala `coincurve` (`pip install coincurve`) en el mismo entorno y `AgentSigner` pasa a funcionar sobre libsecp256k1, a unas 10,000 por segundo, sin ningún cambio en tu código. El SDK no elige un backend de curva por sí mismo; `eth-keys` usa `coincurve` siempre que puede importarlo, salvo que la variable de entorno `ECC_BACKEND_CLASS` nombre otro backend. El benchmark de Python muestra el backend que midió, que es la forma más rápida de confirmar que el cambio funcionó. O firma con HMAC, que nunca es la restricción.
* **TypeScript con clave de agente:** unas 2,900 por segundo alcanzan para el tope de trading en un solo núcleo, pero no para trading y cancelaciones juntos. Un cliente que ejecuta ambos a tasa completa debería firmar con HMAC o repartir la firma entre worker threads.
* **Rust y la CLI:** holgados con cualquiera de los dos esquemas.

Por solicitud, la firma agrega 0.3 ms en TypeScript y 3.5 ms en una instalación predeterminada de Python con clave de agente. Es una fracción pequeña de un viaje de ida y vuelta del cliente que se mide en decenas de milisegundos, pero se nota en la ruta de Python. Es otra razón para instalar `coincurve` si operas desde Python con una clave de agente.

#### Cómo se comparan con las cifras publicadas por Paradex

Paradex publica una tabla similar: unas 5,000 firmas por segundo en Rust, 1,430 en Go, 50 en TypeScript y 8 en Python o Java. Tomados al pie de la letra, los 20 ms por firma de TypeScript limitan un hilo a 50 firmas por segundo. Eso cubre un solo presupuesto de 20/s, pero la firma sola usaría el 40% del núcleo, y no alcanza para los 60/s que puede gastar quien llama con nivel Pro entre solicitudes, acciones de trading y cancelaciones juntas. Esas cifras no se trasladan. Paradex firma las órdenes con una clave de StarkNet, una curva distinta y un hash distinto de cualquiera de los dos esquemas de aquí, y sus números no se midieron en el hardware de abajo, así que una proporción entre las dos tablas es, como mucho, orientativa. El patrón sí se traslada. Un firmador de curva elíptica en código interpretado puro es el caso lento, y los bindings nativos cierran la mayor parte de la brecha. La diferencia aquí es que el caso lento (Python con su alternativa en Python puro, unas 280 por segundo) sigue siendo más de diez veces más rápido de lo que necesita el nivel Pro.

#### Metodología

* **Hardware.** Apple M2, 8 núcleos (4 de rendimiento, 4 de eficiencia), 8 GB, macOS 26.5 (build 25F84), conectado a la corriente y con el Modo de bajo consumo desactivado. macOS no puede fijar un proceso a un núcleo, y la máquina no estaba inactiva en otros aspectos (carga promedio de 4–14 durante las corridas), así que lee la columna p95 y el rango como límites superiores.
* **Runtimes.** Rust 1.97 (perfil release), Node.js 22.23, Python 3.14 para las filas de HMAC y de clave de agente predeterminada. La fila de `coincurve` corre en Python 3.13, porque `coincurve` todavía no publica un wheel para Python 3.14. La fila de clave de agente predeterminada mide lo mismo en 3.13 (3.5 ms), así que el intérprete no explica la diferencia.
* **Fixture.** Idéntico en los tres SDK: `POST`, ruta `/api/v1/orders`, consulta vacía, un cuerpo de orden límite de 155 bytes y una marca de tiempo fija. El firmador de agente emite un nonce nuevo en cada iteración, como lo hace en una escritura real. Ambos esquemas producen firmas idénticas byte a byte entre los SDK para este fixture.
* **Procedimiento.** Dos segundos de calentamiento, luego cada firma se cronometra por separado (Rust 20,000, TypeScript 5,000, Python 3,000 o 5,000) y se toman p50 y p95 de las muestras. Las firmas por segundo son la cantidad de muestras dividida por el tiempo real del ciclo cronometrado. Cada benchmark se ejecutó cinco veces, intercalado con los demás. La tabla muestra la corrida mediana y el rango del p50 en las cinco. El benchmark de Rust también ejecuta criterion, cuya estimación de la media coincidió con el ciclo cronometrado (76–85 µs para la clave de agente).
* **Cómo volver a ejecutarlo.** Cada SDK incluye su benchmark: `cargo bench --bench signing` en `nexus-exchange-rs`, `pnpm bench` en `nexus-exchange-ts` y `python bench/signing_bench.py` en `nexus-exchange-py`. El benchmark de Python muestra qué backend de `eth-keys` midió.

### Cómo diseñar según los límites

* **Agrupa en lotes en lugar de hacer ciclos.** `POST /orders/batch` cobra `1 + floor(n / 40)`, así que 40 órdenes en una solicitud cuestan una cuadragésima parte de 40 envíos individuales.
* **Usa streams en lugar de polling.** Los datos del libro de órdenes y de las operaciones por WebSocket no cuestan nada de tu presupuesto de solicitudes, y llegan antes: el frame de suscripción es un frame entrante, y el stream que sigue es gratis.
* **Presupuesta las lecturas pesadas por su costo real.** `/fills`, `/orders/history`, `/account/summary` y `/account/portfolio-history` cuestan 5 cada una. Consultar las cuatro cada segundo cuesta 20/s, que es todo el presupuesto de quien llama con nivel Pro.
* **Prefiere una sola lectura coherente.** `GET /account/state` devuelve juntos el resumen y todas las posiciones abiertas. Es más barato que dos llamadas y no tiene la condición de carrera entre ellas (consulta [Portafolio y estado de la cuenta](/api-reference/es-419/guides/portfolio.md)).
* **Guarda en caché lo que no cambia.** Los metadatos de mercado de `GET /markets` no necesitan volver a obtenerse en cada ciclo.
* **Regula tu ritmo según los encabezados y según `/account/rate-limit`.** Consultar ese endpoint no tiene costo. Reintentar a ciegas después de un `429`, sí.

### Relacionado

* [Especificación OpenAPI](https://github.com/nexus-xyz/nexus-exchange-api): pesos por operación, clases y semántica de los encabezados, con carácter normativo
* [Redes](/api-reference/es-419/guides/networks.md): cómo se selecciona una red y qué vincula una clave a una
* [Portafolio y estado de la cuenta](/api-reference/es-419/guides/portfolio.md): los endpoints de lectura pesada y cómo leerlos en una sola llamada
* [Límites de solicitudes y conexiones](https://docs.nexus.xyz/exchange/apis-and-rates/rate-limits): ventana HMAC, vida útil de los tokens, asignación del faucet
* [Guía para market makers](https://docs.nexus.xyz/exchange/apis-and-rates/market-maker-guide): cómo solicitar el nivel MarketMaker
* [Descripción general de las interfaces](/api-reference/es-419/readme.md)

> **Estado:** versión preliminar de desarrollo en testnet. Mainnet no se ha lanzado. Cada tope de esta página es configuración actual y no un contrato congelado. Lee `/account/rate-limit` en producción en lugar de fijar un número en el código, y fija una versión publicada de la especificación para que los pesos por operación sobre los que construyes no cambien. El estado del limitador todavía no persiste entre reinicios del gateway. Las credenciales y los saldos de testnet no tienen valor en el mundo real.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.nexus.xyz/api-reference/es-419/guides/rate-limits.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
