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

# API

> Token-based HTTP API for a server's economy, items and leveling.

| | |
| - | - |
| Base URL | `https://percy.klappstuhl.me/api/v1` |
| Reference | [percy.klappstuhl.me/api](https://percy.klappstuhl.me/api) |
| Format | JSON over HTTPS |
| Auth | `Authorization: Bearer pct_...` |

The reference lists every endpoint, field and response.

## Tokens

Create tokens on the dashboard **Developers** page (Manage Server required). A token starts with `pct_`, is shown once, belongs to one server, and a server can hold 10 active tokens. Revoking takes effect immediately. Changes made with a token appear in the change log as `api:<token name>`.

| Scope | Allows |
| - | - |
| `economy:read` | Balances, richest members |
| `economy:write` | Change balances |
| `items:read` | Shop, member inventories |
| `items:write` | Create, edit, delete items; give and take inventory |
| `leveling:read` | Levels and leaderboard |

`GET /guilds/{guild_id}` needs only a valid token for that server. `GET /bot/stats` needs no token.

```bash theme={null}
curl https://percy.klappstuhl.me/api/v1/guilds/GUILD_ID \
  -H "Authorization: Bearer pct_YOUR_TOKEN"
```

## Rate limits

60 requests per minute per token, burst 20 (unauthenticated: 30 per minute per IP). Responses carry `X-RateLimit-Limit`, `X-RateLimit-Remaining` and `X-RateLimit-Reset`. Over the limit returns `429 rate_limited` with `Retry-After` in seconds.

## Idempotency

Send `Idempotency-Key` (1 to 64 characters of `A-Za-z0-9-_.:`) on balance `PATCH`, inventory `POST` and inventory `DELETE`. The same key and request within 24 hours returns the first response with `Idempotent-Replayed: true`. A different request with the same key returns `422 idempotency_key_reuse`; one still running returns `409 request_in_progress`.

## Errors

```json theme={null}
{ "error": { "code": "item_not_found", "message": "Item not found." } }
```

| Status | Codes |
| - | - |
| 400 | `invalid_request`, `invalid_body`, `invalid_id`, `invalid_query`, `unknown_field`, `invalid_idempotency_key`, `insufficient_funds` |
| 401 | `missing_token`, `invalid_token` |
| 403 | `guild_mismatch`, `missing_scope`, `forbidden` |
| 404 | `item_not_found`, `guild_not_found`, `not_found` |
| 409 | `item_exists`, `item_limit_reached`, `insufficient_items`, `request_in_progress`, `conflict` |
| 422 | `idempotency_key_reuse` |
| 429 | `rate_limited` |
| 500, 502, 503 | `internal_error`, `upstream_unavailable`, `unavailable` |

Use `code` in programs; `message` may change. Retry `5xx` and `429`, not other `4xx`.

Examples: [curl, JavaScript and Python](https://percy.klappstuhl.me/docs/api/examples.md). For events pushed to you, use outbound webhooks on the [dashboard](https://percy.klappstuhl.me/docs/dashboard/overview.md).


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