> For the complete documentation index, see [llms.txt](https://docs.hello.trade/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.hello.trade/developer-tools/nonce-and-rate-limits.md).

# Nonce & Rate Limits

## Overview

Every signed request requires a nonce (millisecond timestamp). The system validates nonces using time window validation, replay prevention, and rate limiting.

***

## Nonce Types

### Wallet Nonce

**Used for:** Orders, Withdrawals, Leverage Updates, Authentication, Cancel Orders

* **Format**: Millisecond timestamp as `uint256`
* **Generation**: Current Unix time in milliseconds

```typescript
const nonce = Date.now();
```

```rust
let nonce = U256::from(chrono::Utc::now().timestamp_millis() as u64);
```

Each wallet nonce can only be used once. Generate a fresh timestamp for each operation.

### Token Contract Nonce

**Used for:** ERC-2612 Permit signatures (deposits only)

* **Format**: Sequential `uint256` managed by token contract
* **Source**: Fetch from token contract before signing

```typescript
const tokenNonce = await tokenContract.nonces(walletAddress);
```

```rust
let token_nonce: U256 = token_contract.nonces(wallet_address).call().await?;
```

The nonce for Permit signatures must be fetched from the token contract. Using `Date.now()` for deposit nonces will cause validation failure.

***

## Wallet Nonce Validation

### Validation Rules

| Rule                 | Value             | Description                                           |
| -------------------- | ----------------- | ----------------------------------------------------- |
| **Time Window**      | 5 minutes         | Nonce must be within 5 minutes of current server time |
| **Future Tolerance** | 1 minute          | Tolerance for clock skew between client and server    |
| **Server Restart**   | Server start time | Nonce must be after server restart                    |
| **Uniqueness**       | Per wallet        | Each nonce can only be used once per wallet           |

**Valid nonce range:**

```
current_time - 5 minutes ≤ nonce ≤ current_time + 1 minute
```

***

## Rate Limiting

Two independent limits apply per wallet:

| Limit                     | Value                                             | Applies to                                                                             |
| ------------------------- | ------------------------------------------------- | -------------------------------------------------------------------------------------- |
| **Request rate**          | 20 requests/second (rolling 1-second window)      | Wallet-authenticated requests — REST and WebSocket, including orders and subscriptions |
| **Signed request budget** | 3,000 signed requests per 5-minute rolling window | All signed operations (orders, replaces, cancels, withdrawals, leverage updates)       |

The request rate is hard-enforced over a rolling 1-second window: a request is rejected if 20 have already been made in the trailing second.

The signed request budget allows a sustained rate of \~10 signed operations/second. Each signed operation consumes one nonce; the budget frees up as nonces age out of the 5-minute window. A wallet that exhausts its budget is rejected with error code `4035 SUSTAINED_RATE_LIMIT_EXCEEDED` until older nonces expire.

**Cancels keep working:** cancel and cancel-all operations are granted 2x the signed request budget, so a wallet that has exhausted its sustained budget can still pull its resting orders.

Signed requests consume their nonce before the request rate check, so requests rejected for exceeding the request rate still count against the signed request budget.

### Unauthenticated read endpoints

Read endpoints that take a wallet as a query parameter — account summary, open orders, max order size, required margin, funding history, trade/order reporting, and PnL history — are **not** subject to the per-wallet request rate. They carry no signature, so anyone could name any wallet, and a per-wallet limit on them would let one caller consume another wallet's allowance.

These endpoints are rate limited **per client IP at the edge instead**. Treat them as a shared budget across everything you call from one address, and prefer polling them no faster than your UI actually needs. `max_order_size` in particular is a search over placement validation rather than a cached read: call it when a user asks for a maximum, not on a timer. If you know the size you want and need the collateral for it, use `required_margin` — it is a single evaluation and far cheaper.

***

## Common Errors

| Error                                         | Cause                                 | Solution                                                                                       |
| --------------------------------------------- | ------------------------------------- | ---------------------------------------------------------------------------------------------- |
| `Nonce too old (outside 300000ms window)`     | Nonce older than 5 minutes            | Generate fresh timestamp                                                                       |
| `Nonce too far in future`                     | System clock ahead of server          | Synchronize system clock                                                                       |
| `Nonce already used (replay attack detected)` | Nonce reused                          | Generate new nonce                                                                             |
| `Nonce predates server start`                 | Nonce from before server restart      | Generate new nonce                                                                             |
| `Rate limit exceeded` (4029)                  | More than 20 requests/second          | Reduce request rate                                                                            |
| `Sustained request rate exceeded` (4035)      | Signed request budget exhausted       | Back off; budget frees as nonces age past 5 minutes. Cancels have 2x headroom and keep working |
| `Order not found or already closed` (4041)    | Cancel/replace raced a fill or cancel | Benign — treat as already-closed, do not retry or alert                                        |
| `Signature verification failed` (deposits)    | Incorrect token contract nonce        | Fetch fresh nonce from contract                                                                |

For complete error code reference, see [Error Codes](/developer-tools/error-codes.md).
