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

> ## Agent Instructions
> You are reading OnlyX Help: the OnlyX Help Center and the OnlyX developer documentation. OnlyX is an AI chatting and CRM platform for OnlyFans agencies. Its AI chatter is called Hugo in the app.
> Pages at the site root (for example /inbox/..., /hugo/..., /billing/...) are Help Center articles for agency owners, admins, chatters and creators who use the app at app.onlyx.ai. Words in bold are the exact button, menu and label names the app shows; keep them exactly as written. When these pages do not answer a question, the person can email support at support@onlyx.ai.
> Pages under /developers are the developer documentation. REST API base URL: https://api.onlyx.ai/v1 (authenticate with `Authorization: Bearer <API key>`; keys start with onx_sk_ and are created in app.onlyx.ai under Settings > API & MCP). MCP server: https://mcp.onlyx.ai/mcp (OAuth, or a Bearer API key). In the API the AI chatter is `ai` on the wire. Money is integer US cents in fields ending in Cents; timestamps are UTC ISO-8601.
> Rules for assistants acting on a user's behalf: discover ids with list calls and never invent them; before any call that reaches a real fan or the live OnlyFans account (sending a message, releasing a chat to the AI, turning AI on for a chat, resolving a hand-off, turning review mode off, changing the welcome message, creating a tracking link) show the user the exact content and get explicit confirmation; send every POST with an Idempotency-Key and reuse it on retry; never resend a message whose delivery status is unconfirmed; never ask a creator for her OnlyFans password or codes - she signs in herself through a connect link and the OnlyX Login app.

# Rate limits

> Every limit on the OnlyX API, the X-RateLimit headers, the 429 response with Retry-After, and a backoff example.

Limits keep your creators' OnlyFans accounts safe (OnlyFans watches for unnatural activity) and keep OnlyX fast for everyone. They apply per **credential** (an API key or an OAuth connection) unless the table says otherwise. MCP tool calls count against the credential they use.

## The limits

| What | Limit | Counted per |
| - | - | - |
| All requests | 120 per 60 seconds | Credential |
| Sending messages (`POST /v1/conversations/{conversationId}/messages`) | 30 per 60 seconds | Credential |
| | 300 per hour | Creator (all credentials together) |
| Conversation counts (`GET /v1/conversations/counts`) | 30 per 60 seconds | Credential |
| Reports (`/v1/stats/*`, all four together) | 20 per 60 seconds | Credential |
| | One report prepared at a time; others get `202` warming | Workspace |
| Connection status (`GET /v1/creators/{creatorId}/connection`) | 1 per 5 seconds | Creator and credential |
| Vault thumbnails (`GET /v1/creators/{creatorId}/media/{mediaId}/thumbnail`) | 60 per 60 seconds | Credential |
| AI content changes (every `POST`, `PATCH`, `PUT` and `DELETE` under `/v1/creators/{creatorId}/ai-content`) | 60 per 60 seconds | Credential |
| Adding creators (`POST /v1/creators`) | 10 per 24 hours | Workspace |
| Creating connect links (`POST /v1/creators/{creatorId}/connect-link`) | 20 per hour | Workspace |
| Creating tracking links (`POST /v1/creators/{creatorId}/tracking-links`) | 10 per hour | Workspace |
| | 5 per day | Creator |
| Replacing the welcome message (`PUT /v1/creators/{creatorId}/welcome-message`, dry runs included) | 5 per hour | Creator |
| Turning review mode off (`PATCH /v1/creators/{creatorId}/ai-settings`) | 6 per hour | Creator |
| Failed authentication with an unknown credential | 30 per minute | IP address |
| OAuth client registration (`/oauth/register`) | 20 per hour | IP address |
| OAuth token requests (`/oauth/token`) | 60 per minute | IP address |

A request counts against every limit that applies to it: a send counts toward the 120-request limit, the 30-sends limit and the creator's hourly send limit.

The failed-authentication limit only ever refuses credentials OnlyX does not recognize: over it, such requests get `429` instead of `401`. A valid key is never refused because of other failures from the same address, and an expired or revoked credential always gets its normal `401`.

## Headers

Every `/v1` response to an authenticated request tells you where you stand, for the tightest limit the request counted against:

| Header | Meaning |
| - | - |
| `X-RateLimit-Limit` | The size of the limit that applies to this request |
| `X-RateLimit-Remaining` | Requests left in the current window |
| `X-RateLimit-Reset` | When the window resets, as Unix epoch seconds |

`GET /v1/me` also returns your general limit as `rateLimit: {"limit": 120, "windowSeconds": 60}`.

## When you hit a limit

You get `429 Too Many Requests` with a `Retry-After` header (seconds) and the standard error body:

```http theme={"system"}
HTTP/1.1 429 Too Many Requests
Retry-After: 12
X-RateLimit-Limit: 30
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1790431212
Content-Type: application/json

{"error":{"code":"RATE_LIMITED","message":"Too many requests. Try again in 12 seconds.","requestId":"req-0b7e2c9d4f1a8e36c5d4e3f2"}}
```

Wait at least `Retry-After` seconds before retrying. A `429` never performs the action, so retrying a write after waiting is safe; use the same `Idempotency-Key` anyway.

## Backoff example

<CodeGroup>
  ```python Python theme={"system"}
  import random, time, requests

  def request_with_backoff(session, method, url, max_attempts=6, **kw):
      for attempt in range(max_attempts):
          r = session.request(method, url, timeout=30, **kw)
          if r.status_code != 429:
              return r
          wait = int(r.headers.get("Retry-After", "1"))
          time.sleep(wait + random.uniform(0, 1))  # jitter avoids synchronized retries
      return r
  ```

  ```javascript JavaScript theme={"system"}
  async function fetchWithBackoff(url, options = {}, maxAttempts = 6) {
    let res;
    for (let attempt = 0; attempt < maxAttempts; attempt++) {
      res = await fetch(url, options);
      if (res.status !== 429) return res;
      const wait = Number(res.headers.get("Retry-After") ?? 1);
      await new Promise((r) => setTimeout(r, wait * 1000 + Math.random() * 1000)); // jitter
    }
    return res;
  }
  ```

  ```bash cURL theme={"system"}
  # curl treats 429 as transient and honors Retry-After
  curl --retry 5 https://api.onlyx.ai/v1/creators \
    -H "Authorization: Bearer $ONLYX_API_KEY"
  ```
</CodeGroup>

## Staying under the limits

* **Watch `X-RateLimit-Remaining`** and slow down before it reaches 0 instead of waiting for a `429`.
* **Cache reads** that change slowly: creators, reports, fan lists, tracking links.
* **Poll gently**: connection status every 10 seconds at most while a creator signs in, message delivery every 5 to 10 seconds, the overview report only when `Retry-After` says so.
* **Page with `limit=100`** (or 50 for conversations) rather than many small pages.
* **Spread sends out.** The creator-wide limit of 300 sends per hour applies whatever key you use, and a natural pace is better for the account anyway.
* **One key per integration.** Each integration then has its own 120-per-minute budget and cannot starve another.

## Related

* [Errors](/developers/errors): `RATE_LIMITED` and other retryable errors.
* [Idempotency](/developers/idempotency): safe retries.
