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

# API overview

> Authentication, request format, paging and limits for the public API.

Every Xitter instance has a public JSON API at `https://<instance>/api/v1`. Scripts and bots use it to read and post as their own account. Each instance also documents its API at `/api`.

> [!NOTE]
>
> Running a bot? It must follow the [bot guidelines](/api/bot-guidelines).

What a token sees is what its account sees: blocks, protected accounts and suspensions apply. Posts made through the API show "Xitter API" as their app.

## Personal tokens

Make a token at `/account/api`. A **read** token can only look; a **write** token can also post, like and follow. Send it with every request:

```http theme={null}
Authorization: Bearer xit_...
```

> [!WARNING]
>
> Anyone holding a token can act as you. Changing or resetting your password revokes all API tokens, so make new ones for your scripts and bots afterward.

## Apps for other people (OAuth 2)

For an app used by other people, register a public client at `/account/apps/developer`. Users review and revoke grants at `/account/apps`.

The flow is OAuth 2 authorization code with mandatory PKCE (S256). Clients have no shared secret.

**1. Make a verifier and challenge**

Generate a random 43–128 character `code_verifier` and its SHA-256 base64url `code_challenge`. Generate a random `state`.

**2. Send the user to authorize**

Open `https://<instance>/oauth/authorize` with `response_type=code`, your `client_id`, the exact registered `redirect_uri`, `scope=read` or `write`, `state`, `code_challenge` and `code_challenge_method=S256`.

**3. Exchange the code**

After consent, check `state`, then form-POST the returned `code` with `grant_type=authorization_code`, `client_id`, `redirect_uri` and `code_verifier` to `https://<instance>/oauth/token`.

**4. Call the API**

Use `access_token` as the Bearer token.

Codes work once, for five minutes. Access tokens expire after 30 days; reauthorize to get a new one. HTTPS redirects and HTTP loopback redirects are accepted, and the redirect must match the registered URL exactly.

### One app for every Xitter

Instead of registering on each instance, an app can use the HTTPS URL of a JSON document it hosts as its `client_id` (an OAuth client ID metadata document):

```json theme={null}
{
  "client_id": "https://app.example/oauth-client.json",
  "client_name": "My app",
  "redirect_uris": ["https://app.example/"],
  "logo_uri": "https://app.example/icon.png",
  "token_endpoint_auth_method": "none"
}
```

* `client_id` must be the document's own URL, exactly.
* `redirect_uris` must be HTTPS on the document's host.
* `logo_uri` is optional: an HTTPS image on that host, shown as the app's icon.

Instances that support this say so with `client_id_metadata_document_supported` in `/.well-known/oauth-authorization-server`.

## Requests and responses

Bodies are JSON (or a form). Answers are JSON with the result in `data`, or `{"error": "..."}` with a 4xx or 5xx status.

```bash theme={null}
curl -X POST https://xit.example.org/api/v1/posts \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"text": "hello from the API"}'
```

The API sends CORS headers for any origin, since tokens are sent explicitly and never as cookies.

## Paging

Lists take `limit` (20 by default, 100 at most). Lists that page return `next_cursor`: pass it back as `cursor` for the next page. It is `null` at the end.

## Limits

The same as in the app, per 15 minutes:

| Bucket | Limit |
| - | - |
| All requests | 6000 |
| Posts | 150 |
| Likes, reposts, bookmarks and follows together | 1000 |
| Uploads started | 150 |

Every answer carries `x-rate-limit-limit`, `x-rate-limit-remaining` and `x-rate-limit-reset` (a Unix time). Over a limit you get `429` with `retry-after`.

## Errors

| Status | Meaning |
| - | - |
| `401` | No valid token. |
| `403` | A read token tried to write. |
| `404` | No such endpoint or object. |
| `413` | The request is too large. |
| `429` | Over a rate limit. |
| `503` | The instance is in maintenance mode. |


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