> ## Documentation Index
> Fetch the complete documentation index at: https://docs.ralphstudio.xyz/llms.txt
> Use this file to discover all available pages before exploring further.

# Rate Limits

> Per-plan limits, response headers, and strategies for staying within them.

Every request to the Ralph Studio API counts against your plan's rate limit. Requests that exceed the limit are rejected with a `429` response they are not queued or delayed.

## How limits work

Rate limits are measured in two ways simultaneously:

* **Requests per second (RPS)**: a burst limit on how many requests you can send in any single second
* **Requests per month**: a rolling total across your billing period

Both limits apply at the same time. You can hit the monthly cap without ever triggering the per-second limit, and vice versa.

## Per-plan limits

| Plan       | Requests per second | Requests per month |
| ---------- | ------------------- | ------------------ |
| Free       | 5                   | 100,000            |
| Starter    | 25                  | 1,000,000          |
| Pro        | 100                 | 10,000,000         |
| Enterprise | Custom              | Custom             |

Limits apply per API key, not per account. If you have multiple keys on the same plan they each get the full limit.

## Rate limit headers

Every response includes headers showing your current limit status:

```
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 87
X-RateLimit-Reset: 1748476860
```

| Header                  | Description                                   |
| ----------------------- | --------------------------------------------- |
| `X-RateLimit-Limit`     | Your plan's requests per second limit         |
| `X-RateLimit-Remaining` | Requests remaining in the current second      |
| `X-RateLimit-Reset`     | Unix timestamp when the current window resets |

Read these headers on every response and slow down before `X-RateLimit-Remaining` reaches zero.

## 429 response

When you exceed the limit:

```bash theme={null}
curl "https://rpc.ralphstudio.xyz/{slug}/infos/version" \
  -H "Authorization: Bearer API_KEY"
```

```json theme={null}
{
  "detail": "Rate limit exceeded"
}
```

The response still includes the rate limit headers so you know exactly when to retry:

```
HTTP/1.1 429 Too Many Requests
X-RateLimit-Limit: 25
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1748476861
```

Do not retry immediately. Wait until `X-RateLimit-Reset` before sending the next request.

## Handling 429s in a script

```bash theme={null}
while true; do
  response=$(curl -s -D /tmp/headers.txt -o /tmp/body.json -w "%{http_code}" \
    "https://rpc.ralphstudio.xyz/{slug}/infos/version" \
    -H "Authorization: Bearer API_KEY")

  if [ "$response" = "429" ]; then
    reset=$(grep -i "x-ratelimit-reset" /tmp/headers.txt | awk '{print $2}' | tr -d '\r')
    now=$(date +%s)
    wait=$((reset - now + 1))
    echo "Rate limited. Waiting ${wait}s..."
    sleep $wait
    continue
  fi

  cat /tmp/body.json
  break
done
```

## Strategies for staying within limits

**Batch with multicall**

Instead of calling `call-contract` once per token in a list, use `multicall-contract` to fetch all results in a single request:

```bash theme={null}
curl -X POST "https://rpc.ralphstudio.xyz/{slug}/contracts/multicall-contract" \
  -H "Authorization: Bearer API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "calls": [
      { "group": 0, "address": "27Gsc5...", "methodIndex": 0, "args": [] },
      { "group": 0, "address": "28Htd6...", "methodIndex": 0, "args": [] },
      { "group": 0, "address": "29Iue7...", "methodIndex": 0, "args": [] }
    ]
  }'
```

One request instead of three.

**Use wider time windows for block queries**

Querying blocks in a single large window costs one request. Querying the same range in ten small windows costs ten:

```bash theme={null}
# One request preferred
curl "https://rpc.ralphstudio.xyz/{slug}/blockflow/blocks?fromTs=1748390400000&toTs=1748476800000" \
  -H "Authorization: Bearer API_KEY"
```

**Cache responses that do not change**

Some data is immutable once written. Cache these aggressively:

| Endpoint                                 | Changes?     | Suggested cache TTL |
| ---------------------------------------- | ------------ | ------------------- |
| `/contracts/{address}/state` immFields   | Never        | Forever             |
| `/contracts/{codeHash}/code`             | Never        | Forever             |
| `/infos/chain-params`                    | Never        | Forever             |
| `/transactions/details/{txId}` confirmed | Never        | Forever             |
| `/contracts/{address}/state` mutFields   | On each tx   | 5–15 seconds        |
| `/addresses/{address}/balance`           | On each tx   | 5–15 seconds        |
| `/infos/current-hashrate`                | Continuously | 30 seconds          |

**Poll at a reasonable interval**

If you are watching for new transactions or blocks, polling faster than one block time gives you no new data but burns requests. Alephium produces one block every 16 seconds per chain on average.

```bash theme={null}
# Check for new blocks every 16 seconds
while true; do
  curl "https://rpc.ralphstudio.xyz/{slug}/blockflow/chain-info?fromGroup=0&toGroup=0" \
    -H "Authorization: Bearer API_KEY"
  sleep 16
done
```

## Next steps

<CardGroup cols={2}>
  <Card title="Error handling" icon="triangle-exclamation" href="/guides/error-handling">
    Full error code reference and retry logic
  </Card>

  <Card title="Authentication" icon="key" href="/authentication">
    API keys, slugs, and header format
  </Card>
</CardGroup>
