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

# Limits & quotas

> Your daily quota, the Pup rate limit, and the headers that report them.

## Daily quota

Each search takes **1 search** from your daily quota. API access comes with Hound and Alpha.

| Plan | Price | Searches per day | Rate limit | API |
| - | - | - | - | - |
| Pup | Free | 100 | 1 search every 3 seconds | `/v1/me` and `/v1/modules` only |
| Hound | \$10 / 30 days | 500 | None | Yes |
| Alpha | \$30 / 30 days | Unlimited | None | Yes |

* The quota resets **every day at 00:00 UTC**. `usage.resetAt` in [`/v1/me`](https://docs.dis.dog/api-reference/endpoints/me) gives the exact moment.
* It is **shared with the website**: a search on dis.dog and a search through the API take from the same quota.
* Unused searches do not carry over to the next day.
* Paid plans are paid in crypto through OxaPay on the [pricing page](https://dis.dog/pricing). A payment lasts 30 days and does not renew by itself; paying again for the same plan adds 30 days to its end. When it ends, the account is back on Pup.

### What takes a search

| Call | Search taken? |
| - | - |
| `GET /v1/search` that answers `200` | Yes |
| A single-module route (`/v1/profile/{id}`, `/v1/connections/{id}`, `/v1/servers/{id}`, `/v1/messages/{id}`, `/v1/roblox/{id}`, `/v1/gunslol/{id}`, `/v1/lookup/{name}`, `/v1/invite/{code}`) that answers `200` or `404` | Yes |
| An input refused before the lookup (`400 invalid_id`, `invalid_name`, `invalid_invite`) | No |
| A Pup key on a paid route (`403 plan_has_no_api`) | No |
| A query DisDog does not recognise (`400 invalid_query`) or a missing `q` (`400 invalid_request`) | No |
| A [removed Discord ID](https://docs.dis.dog/data-removal.md) (`451 removed_by_owner`) | No |
| A search refused by a limit (`429 rate_limited`, `429 quota_exceeded`) | No |
| `GET /v1/me`, `GET /v1/modules`, `GET /v1/health` | No |

The input is checked first, then the removals, and only then is a search taken: a refused call never costs anything. A `404` on a single-module route is an answer (“nothing there”), so it counts.

## Rate limit

On **Pup**, two searches must be at least **3 seconds** apart. The limit belongs to the **account** and applies to the website (Pup has no search access on the API). A search sent too early is refused with `429 rate_limited`, and `retryAfterMs` says how long to wait.

Hound and Alpha have no rate limit.

## Headers

Every call that takes a search, and every `GET /v1/me`, carries your quota in its headers:

| Header | Meaning |
| - | - |
| `X-RateLimit-Limit` | Searches per day on your plan, or `unlimited` on Alpha. |
| `X-RateLimit-Remaining` | Searches left today, after this call, or `unlimited` on Alpha. |
| `X-RateLimit-Reset` | Next reset (00:00 UTC), as a Unix timestamp in seconds. |

The API answers browsers from any origin and exposes these three headers to them, so the [playground](https://docs.dis.dog/api-reference/introduction.md) shows them too.

## Handling `429`

A `429` says why in its body:

```json theme={"system"}
{ "error": "rate_limited", "resetAt": "2026-11-01T00:00:00.000Z", "limit": 100, "retryAfterMs": 1840 }
```

```json theme={"system"}
{ "error": "quota_exceeded", "resetAt": "2026-11-01T00:00:00.000Z", "limit": 100 }
```

`rate_limited` (Pup only, so in practice on the website): wait `retryAfterMs` milliseconds, then try again. `quota_exceeded`: today’s searches are used up, and retrying before `resetAt` will not help.

```python theme={"system"}
import os
import time
import requests

session = requests.Session()
session.headers["Authorization"] = f"Bearer {os.environ['DISDOG_KEY']}"

def search(query, tries=3):
    for _ in range(tries):
        response = session.get("https://api.dis.dog/v1/search", params={"q": query}, timeout=60)
        if response.status_code != 429:
            response.raise_for_status()
            return response.json()
        body = response.json()
        if body["error"] == "quota_exceeded":
            raise RuntimeError(f"Daily quota used up, resets at {body['resetAt']}")
        time.sleep(body.get("retryAfterMs", 3000) / 1000)
    raise RuntimeError("Still rate limited, try again later.")
```

> [!TIP]
>
> Running batches? Read `X-RateLimit-Remaining` after each call, or `GET /v1/me` (free) before you start. Hound and Alpha have no rate limit; Alpha has no daily quota either.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.