# Visão geral da API

A API do Zynko é a mesma que os apps usam: HTTP com JSON para ler e mudar as coisas, e um
[gateway](https://docs.zynko.org/api/gateway.md) WebSocket para receber o que acontece em tempo real. Um bot usa as
duas com o token dele.

| | |
|---|---|
| **Base da API** | `https://zynko.org/api` |
| **Gateway** | `wss://zynko.org/api/gateway` |
| **Formato** | JSON (UTF-8), exceto envio de arquivos (`multipart/form-data`) |

Todas as rotas desta referência são relativas à base. `GET /users/@me` quer dizer
`GET https://zynko.org/api/users/@me`.

## Autenticação

Mande o token no cabeçalho `Authorization`:

```http
GET /api/users/@me HTTP/1.1
Host: zynko.org
Authorization: Bot bot_3f9a...e1
```

O servidor aceita os prefixos `Bot ` e `Bearer ` do mesmo jeito. Tokens de bot começam com
`bot_` seguido de 64 dígitos hexadecimais e **não expiram**: valem até o dono gerar um novo
(`POST /users/@me/bots/{bot_id}/token`) ou apagar o bot. Quando isso acontece, as conexões
abertas no gateway com o token antigo caem com o código `4000`.

Sem token, ou com um token inválido, as rotas respondem `401 unauthorized`. Algumas coisas
são só para pessoas (criar servidor, entrar por convite, criar bots, fazer amizade); nessas
um bot recebe `403` ou `400`. A [lista de rotas](https://docs.zynko.org/api/rotas.md) marca cada uma.

## IDs

Todo id (usuário, servidor, canal, mensagem, cargo, emoji, anexo) é um *snowflake* de 64
bits e **viaja como string** no JSON, porque não cabe num `number` do JavaScript sem perder
precisão:

```json
{ "id": "1234567890123456789", "channel_id": "1234567890123456000" }
```

No corpo das requisições o servidor aceita ids como string ou como número, mas mande
string. Nos caminhos (`/channels/{channel_id}`) eles vão como número decimal.

Um snowflake guarda o momento em que foi criado: os 42 bits de cima são milissegundos
desde **2026-01-01T00:00:00Z** (`1767225600000` em Unix ms), e os 22 de baixo são uma
sequência. Ordenar por id é ordenar por criação.

```js
const EPOCH = 1767225600000n;
const criadoEm = (id) => new Date(Number((BigInt(id) >> 22n) + EPOCH));

criadoEm(msg.id); // Date de quando a mensagem foi enviada
```

O contrário também funciona: `(BigInt(ms) - EPOCH) << 22n` é o menor id possível naquele
instante, útil para paginar mensagens a partir de uma data (`?after=`).

## Datas e outros valores

- Datas são **números**: milissegundos desde a época Unix (`timestamp`, `edited_timestamp`,
  `joined_at`, `expires_at`, `since`, `created_at`).
- Permissões são **números** (bits; cabem em 18 bits). Veja [Permissões](https://docs.zynko.org/api/permissoes.md).
- Cores de cargo são inteiros `0xRRGGBB` ou `null`; a cor de destaque do perfil é uma string
  `"#rrggbb"`.
- Rotas que só confirmam algo respondem `{ "ok": true }`.

## Erros

Os erros da API têm sempre o mesmo formato:

```json
{ "code": "forbidden", "message": "Você não tem permissão para isso" }
```

`message` é uma frase em português pronta para mostrar a uma pessoa; programe contra
`code` e o status HTTP.

| Status | `code` | Quando |
|---|---|---|
| 400 | `bad_request` | Dado inválido ou ação impossível (nome longo demais, mensagem vazia, canal errado...). |
| 401 | `unauthorized` | Sem token, ou token inválido. |
| 403 | `forbidden` | Falta permissão, ou a rota é só para pessoas. |
| 403 | `email_unverified` | Login de uma conta com e-mail não confirmado. Não acontece com bots. |
| 404 | `not_found` | Não existe **ou você não tem acesso**. |
| 409 | `conflict` | Nome já em uso (por exemplo o `username` de um bot novo). |
| 413 | `too_large` | Arquivo grande demais. |
| 429 | `rate_limited` | Limite de requisições estourado. |
| 429 | `slow_mode` | O modo lento do canal ainda não deixou mandar de novo. |
| 500 | `internal` | Erro do servidor. |
| 503 | `unavailable` | Recurso não configurado neste servidor (arquivos, voz). |

> **404 em vez de 403**
>
> Para que não dê para sondar ids, um servidor de que você não é membro, ou um canal que você
> não pode ver, responde `404`, como se não existisse. `403` aparece quando você **vê** a
> coisa mas não pode fazer aquilo com ela.

Erros que o servidor nem chega a processar não seguem esse formato: um JSON malformado, um
corpo sem `Content-Type: application/json` ou um id inválido no caminho voltam com `400`,
`415` ou `422` e uma mensagem em texto puro.

### Limites de requisição (429)

Quando um limite estoura, a resposta é `429` com o tempo de espera em milissegundos no corpo
e em segundos no cabeçalho `Retry-After`:

```http
HTTP/1.1 429 Too Many Requests
Retry-After: 4

{ "code": "rate_limited", "message": "Calma! Você está indo rápido demais", "retry_after_ms": 3712 }
```

O modo lento de um canal responde do mesmo jeito, com `code: "slow_mode"`.

Os limites são contados por conta (o bot inteiro, não por canal), em janelas fixas. Os que
importam para um bot:

| Ação | Rota | Limite |
|---|---|---|
| Enviar mensagem | `POST /channels/{id}/messages` | 10 a cada 10 s |
| Editar mensagem | `PATCH /channels/{id}/messages/{id}` | 10 a cada 10 s |
| Reagir | `PUT .../reactions/{emoji}` | 20 a cada 10 s |
| Digitando | `POST /channels/{id}/typing` | 10 a cada 10 s |
| Enviar anexo | `POST /channels/{id}/attachments` | 30 por minuto |
| Enviar imagem (avatar, ícone, emoji) | `POST /media` | 10 por minuto |
| Criar postagem em fórum | `POST /channels/{id}/posts` | 10 por minuto |
| Editar perfil | `PATCH /users/@me` | 20 por minuto |
| Criar convite | `POST /guilds/{id}/invites` | 20 por hora |
| Entrar numa sala de voz | `POST /channels/{id}/voice` | 20 por minuto |
| Trocar o servidor de voz da sala | `PUT /channels/{id}/voice/server` | 10 por minuto |

Apagar mensagens, tirar reações e as rotas de gerenciamento não têm limite próprio.

Além disso, cada canal pode ter **modo lento** (`rate_limit_per_user`, em segundos): depois de
mandar uma mensagem (ou abrir uma postagem), a mesma conta espera esse tempo antes da próxima.
Quem tem **Gerenciar mensagens** ou **Gerenciar canais** no canal não espera.

## Imagens e arquivos

Os campos de imagem (`avatar`, `banner`, `icon`, `url` de emoji) guardam um destes:

- um caminho **relativo** do próprio Zynko, `/api/media/{id}/{segredo}`: público, sem
  autenticação, com cache longo. Para usar, junte com a origem: `https://zynko.org/api/media/...`;
- uma URL **absoluta** de GIF do KLIPY (`https://static.klipy.com/...`), usada como está.

```js
const urlDaImagem = (v) => (v?.startsWith('/') ? 'https://zynko.org' + v : v);
```

Para trocar uma imagem, envie o arquivo em `POST /media` (PNG, JPEG, GIF, WebP ou AVIF, até
16 MB), pegue o `id` que volta e mande-o como `avatar_id`, `banner_id`, `icon_id` ou
`image_id` na rota que usa a imagem. Uploads que não forem usados somem em um dia.

**Anexos de mensagens** são outra coisa. Cada canal tem sua chave e os arquivos ficam
cifrados; o `url` de um anexo é `/api/attachments/{id}` e só quem pode ver o canal consegue
baixar, mandando o token. Qualquer outra pessoa recebe
`404`. Os downloads aceitam `Range`. Tipos que o navegador pode exibir (imagens, vídeo e áudio
comuns) vêm com o `Content-Type` original; o resto vem como `application/octet-stream`.

- Vídeos podem ter uma miniatura em `/api/attachments/{id}/thumb` (campo `thumbnail`).
- Emojis do servidor também estão em `/api/emojis/{id}`, que redireciona para a imagem, sem
  autenticação.
- Imagens de prévias de links (`embeds[].image.url`) passam por `/api/embeds/image?...`.

Veja [Arquivos](https://docs.zynko.org/api/rotas.md#arquivos) para os detalhes do envio.

## Texto das mensagens

O conteúdo é texto com marcação no estilo do Discord. Menções e emojis do servidor ficam
dentro do texto:

| Escreva | Para |
|---|---|
| `<@ID_DO_USUARIO>` | mencionar alguém (a pessoa recebe notificação) |
| `<:nome:ID_DO_EMOJI>` | um emoji do servidor |
| `<a:nome:ID_DO_EMOJI>` | um emoji animado do servidor |

Não há lista separada de menções na mensagem: procure `<@id>` no `content`.

## Próximos passos

- [Gateway](https://docs.zynko.org/api/gateway.md): conectar e receber eventos.
- [Eventos](https://docs.zynko.org/api/eventos.md): tudo o que chega pelo gateway.
- [Rotas](https://docs.zynko.org/api/rotas.md): todas as rotas que um bot pode usar.
- [Objetos](https://docs.zynko.org/api/objetos.md): os formatos JSON.
- [Permissões](https://docs.zynko.org/api/permissoes.md): os bits, os cargos e os canais.
