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

# Rate Limits

> Understand request limits across the API and Relay, and how to handle throttling.

## Overview

Rate limits protect Snipp from abuse and keep performance consistent for everyone. Limits apply per user, per endpoint, except where two endpoints are marked as sharing a bucket below.

## API Limits

| Endpoint                                    | Limit               | Window         |
| ------------------------------------------- | ------------------- | -------------- |
| `GET /users/{id}`                           | No limit            |                |
| `GET /posts/{code}`                         | 20 requests         | Per 30 seconds |
| `POST /upload`                              | 20 requests         | Per 30 seconds |
| `GET /uploads`                              | 20 requests         | Per 30 seconds |
| `PATCH /editUpload`                         | 20 requests         | Per 30 seconds |
| `POST /appendUpload`                        | 10 requests         | Per minute     |
| `DELETE /deleteUpload`                      | 20 requests         | Per 30 seconds |
| `POST /report-post` and `POST /report-user` | 3 requests combined | Per minute     |
| `GET /usage-history`                        | 30 requests         | Per minute     |
| `GET /analytics`                            | 30 requests         | Per minute     |
| `GET /gifs`                                 | 60 requests per IP  | Per minute     |

`POST /upload` also has an abuse safeguard. Sending more than 8 uploads within one second suspends your account. Suspended accounts lose upload access and must contact support to appeal. Team API keys are throttled with a `429` instead of being suspended.

## Relay Limits

The Relay API matches the limits above for shared endpoints, with these additional Relay-only endpoints:

| Endpoint                    | Limit       | Window                                                              |
| --------------------------- | ----------- | ------------------------------------------------------------------- |
| `GET /discover`             | No limit    |                                                                     |
| `GET /blocks`               | No limit    |                                                                     |
| `POST /block`               | 10 requests | Per minute                                                          |
| `POST /unblock`             | 10 requests | Per minute                                                          |
| `POST /follow`              | 30 requests | Per minute                                                          |
| `POST /unfollow`            | 30 requests | Per minute                                                          |
| `GET /followers`            | 30 requests | Per minute                                                          |
| `GET /following`            | 30 requests | Per minute                                                          |
| `PATCH /profile`            | 10 requests | Per minute                                                          |
| `POST /profile/avatar`      | 10 requests | Per minute                                                          |
| `POST /profile/banner`      | 10 requests | Per minute                                                          |
| `PATCH /theme`              | 20 requests | Per minute                                                          |
| `POST /like`                | 30 requests | Per minute, shared with `POST /comment-like`                        |
| `GET /comments`             | No limit    |                                                                     |
| `POST /comment`             | 5 requests  | Per minute, shared with `DELETE /comment`                           |
| `DELETE /comment`           | 5 requests  | Per minute, shared with `POST /comment`                             |
| `POST /comment-like`        | 30 requests | Per minute, shared with `POST /like`                                |
| `POST /report-comment`      | 3 requests  | Per minute, shared with `POST /report-post` and `POST /report-user` |
| `GET /notifications`        | 60 requests | Per minute                                                          |
| `GET /notifications/unread` | 60 requests | Per minute                                                          |
| `POST /notifications/read`  | 60 requests | Per minute                                                          |
| `GET /notification-prefs`   | 20 requests | Per minute                                                          |
| `POST /notification-prefs`  | 20 requests | Per minute                                                          |

`GET /posts/{code}` and `GET /discover` on Relay automatically count views per post. Views are deduplicated per IP and post: up to 3 counted views per IP per post per hour.

See the [Relay Reference](/relay-reference/introduction) for what Relay covers and how to authenticate.

## Rate Limit Headers

Rate-limited responses include headers to help you track your usage:

| Header                  | Description                                                   |
| ----------------------- | ------------------------------------------------------------- |
| `X-RateLimit-Limit`     | Maximum requests allowed per window                           |
| `X-RateLimit-Remaining` | Requests remaining in the current window                      |
| `X-RateLimit-Reset`     | Unix timestamp (seconds) when the window resets               |
| `Retry-After`           | Seconds to wait before retrying. Sent on `429` responses only |

Endpoints with no limit do not include these headers.

## Rate Limit Responses

When you exceed the limit, the API returns HTTP status `429`:

```json theme={null}
{
  "error": "Rate limit exceeded. Please try again later."
}
```

The rate limit headers are still included on `429` responses so you know when to retry.

## Weekly Usage Limit Responses

Separate from per-endpoint rate limits, every account has a [weekly usage limit](/concepts/plans#weekly-usage-limit). Files that would push you over the limit are rejected before they are stored. The exact response shape depends on the endpoint:

* `POST /upload` and `POST /appendUpload` return `200` with the rejected file moved to the `failed` array. Each entry includes `error: "Weekly usage limit exceeded."`, plus `quota`, `used`, and `resetsAt`.
* The Website internal chunked-upload route returns `413` with the same fields at the top level.
* The Website internal `/api/v1/album` route moves the rejected file to the `failed` array like `/upload`: `200` when at least one file was stored, `400` when every file failed. The fields sit at the top level only when a single file was sent.

Check your remaining usage anytime via `GET /users/@me` (`limits.usage`).

## Handling Rate Limits

<Steps>
  <Step title="Check the headers">
    Read `X-RateLimit-Remaining` from each response. When it approaches `0`, slow down.
  </Step>

  <Step title="Detect the 429 status">
    Check for HTTP status `429` in your API responses.
  </Step>

  <Step title="Wait until reset">
    Use the `Retry-After` header on the `429` as the wait time in seconds, or calculate it from `X-RateLimit-Reset`.
  </Step>

  <Step title="Use exponential backoff">
    If requests continue to fail, double the wait time with each retry (for example, 1s, 2s, 4s, 8s).
  </Step>
</Steps>

## Best Practices

* **Space out bulk uploads.** When uploading multiple files, add a short delay between each request rather than sending them all at once.
* **Cache user data.** Avoid calling `/users/@me` repeatedly. Fetch it once and reuse the result for the duration of your session.
* **Batch where possible.** Reduce the total number of API calls by combining logic on your end instead of making multiple requests for related data.
* **Monitor your usage.** If you consistently hit rate limits, consider whether your integration can be optimized to make fewer requests.
