# Referência da API HTTP

## Idiomas e códigos de erro

Inglês é o padrão. A API, o console da Web e os renderizadores de notificação compartilham os catálogos incorporados em `internal/i18n/locales/` . `internal/i18n/languages.json` define estes códigos canônicos e nomes nativos:

| Código    | Idioma             |
| --------- | ------------------ |
| `en`      | English            |
| `zh-CN`   | 简体中文           |
| `zh-Hant` | 繁體中文           |
| `ja`      | 日本語             |
| `ko`      | 한국어             |
| `de`      | Deutsch            |
| `fr`      | Français           |
| `es`      | Español            |
| `pt-BR`   | Português (Brasil) |

- Na primeira visita, o console usa o `Accept-Language` do navegador. Seu seletor armazena localmente o código canônico escolhido. Mudar o idioma do console deixa as configurações de notificação salvas inalteradas.
  As solicitações de API
- , incluindo solicitações de gerenciamento de aplicativos, negociam `Accept-Language` por pesos de qualidade. As respostas incluem `Content-Language` e `Vary: Accept-Language` . As preferências não suportadas são ignoradas; preferências ausentes, inválidas ou totalmente sem suporte voltam para `en` . Um idioma com peso 0 é excluído da negociação.
- As variantes regionais são mapeadas para o idioma suportado: `fr-CA` → `fr` , `es-MX` → `es` , `pt` / `pt-PT` → `pt-BR` . A escrita chinesa é respeitada: `zh-Hans` / `zh-CN` / `zh-SG` → `zh-CN` ; `zh-Hant` / `zh-TW` / `zh-HK` / `zh-MO` → `zh-Hant` . Um script explícito tem precedência sobre região; `zh` simples usa chinês simplificado.
- `GET /locales/default.json` atende o catálogo negociado; `GET /locales/{canonical-code}.json` atende esse catálogo explicitamente. Caminhos de catálogo desconhecidos retornam `locale_not_supported` .
- Configurações de entrega `language` controla notificações geradas pelo posto independentemente da solicitação ou do idioma do console. Ele aceita os códigos canônicos e as variantes regionais suportadas, persiste o código canônico e o padrão é `en` quando omitido ou vazio. Um valor explícito não suportado retorna 400 `config_language_invalid` .
- O serviço de envio de notificações gera texto de notificação de teste nativo usando o idioma do dispositivo emparelhado. O idioma de notificação do posto não substitui esse idioma. O serviço de envio de notificações e o aplicativo suportam seu próprio conjunto de idiomas.
- As funções de pasta padrão e os nomes de pasta comuns estão localizados no console. Caminhos IMAP brutos, nomes personalizados e `folder_roles` permanecem inalterados nas APIs; Os aplicativos localizam essas funções com seus próprios catálogos. Os títulos de notificação continuam a usar o nome da pasta folha original. Os nomes inseridos pelo usuário, assuntos de e-mail, conteúdo de e-mail e códigos de verificação permanecem literais.
- Os logs e a saída CLI usam o inglês. Os erros de negócios mantêm códigos `snake_case` em inglês estáveis e parâmetros nomeados; o armazenamento mantém códigos e parâmetros e as camadas de exibição traduzem mensagens. As datas e os números nas respostas da API mantêm seus formatos existentes legíveis por máquina; o console formata carimbos de data/hora usando a localidade escolhida.

```json
{
  "error": {
    "code": "unauthorized",
    "message": "Sign in with a valid session or API token."
  }
}
```

`last_error` nos registros de entrega e `notice` no status da pasta usam o mesmo formato `{code, message, params?}`, por exemplo `bark_http_error` com `{"status":"503"}` . Filial em `code` ; mostre `message`.

Cada caixa de correio reserva uma conexão para descoberta de pasta e testes de conexão. A demanda do observador é `realtime Folder count + (1 if any scheduled Folders exist, otherwise 0)` , no máximo conexões `connection_limit - 1` (9 por padrão); todas as operações dessa caixa de correio juntas permanecem dentro de `connection_limit` (2–100). Configurações salvas com limite de 1 inicialização em modo de recuperação com `configuration_invalid` .

## API HTTP

`GET /` atende a página atual; ativos estáticos e `/healthz` são públicos. Antes da configuração, todos os outros terminais de gerenciamento retornam 403 `setup_required` . `POST /api/v1/setup` está disponível uma vez; `POST /api/v1/session` é público após a configuração. Todas as APIs restantes requerem o cookie de sessão ou `Authorization: Bearer mwk_…` .
As sessões de cookies usam HttpOnly, SameSite=Strict, Path=/, Secure em uma conexão TLS ou HTTPS Origin, um tempo limite de inatividade de sete dias e um tempo limite absoluto de 30 dias. Cada mutação autenticada por cookie requer `X-CSRF-Token` e um HTTP(S) `Origin` cujo host e porta opcional correspondem exatamente ao host da solicitação. As solicitações com Bearer ignoram as verificações de CSRF. Um cabeçalho de autorização inválido falha mesmo quando um cookie válido está presente.

As falhas de login e código de configuração compartilham um orçamento de endereço de origem: dez falhas a cada 15 minutos, seguidas por 429 `too_many_attempts` com `Retry-After` em segundos. A fonte é Gin ClientIP usando os intervalos de proxy confiáveis acima. As alterações de senha também usam esse orçamento. Origens explícitas entre sites são rejeitadas no login e na configuração. Como cada par de rede privada é confiável como proxy, um cliente em sua rede local pode definir X-Forwarded-For e espalhar suas tentativas por vários endereços de origem. Não exponha o ouvinte do posto a uma rede local não confiável; publique-o apenas por meio de seu proxy reverso.

Todos os corpos JSON são limitados a 64 KiB; campos desconhecidos ou JSON final retornam 400. As senhas têm no mínimo 12 caracteres e no máximo 1024 bytes UTF-8. Nomes de usuário e nomes de token têm de 1 a 128 bytes. Todos os carimbos de data/hora da API de gerenciamento são strings RFC 3339 em UTC, incluindo entrega `created_at` / `accepted_at` , token `created_at` / `last_used_at` , verificações de pastas, tempos de log e tempo de geração de diagnóstico. Os segundos fracionários preservam a precisão armazenada. O token não utilizado `last_used_at` é nulo; entregas sem aceitação omitem `accepted_at` . Contagens, durações e revisões permanecem números.

401 identifica uma sessão ou token de API inválido ou credenciais rejeitadas em `POST /api/v1/session` . Um código de configuração incorreto retorna 400 `setup_code_invalid`; o assistente retorna à etapa de código e preserva o nome de usuário. Uma senha atual incorreta em `PUT /api/v1/admin/password` retorna 400 `current_password_invalid` e conta para o limite de falha; a sessão atual permanece válida. Falhas de login e erros de senha atual aparecem no formulário, preservando suas entradas.

| Método             | Caminho                               | Solicitação / resposta                                                                                                                 |
| ------------------ | ------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
| POST               | `/api/v1/setup`                       | `{ "code":"XXXX-XXXX-XXXX", "username":"admin", "password":"…" }` ; 201, cookie + `{ "csrf_token":"…" }`; repetir configuração: 409    |
| POST               | `/api/v1/session`                     | `{ "username":"admin", "password":"…" }` ; 200, cookie + token CSRF                                                                    |
| GET                | `/api/v1/session`                     | `{ "authenticated":true, "csrf_token":"…" }` ; Bearer retorna `method: "token"` em vez de CSRF                                         |
| DELETE             | `/api/v1/session`                     | 204; revoga a sessão de cookies atual; requer uma sessão                                                                               |
| PUT                | `/api/v1/admin/password`              | `{ "current_password":"…", "password":"…" }` ; 204, revoga outras sessões; Bearer revoga todas as sessões                              |
| POST               | `/api/v1/tokens`                      | `{ "name":"automation" }` ; 201, `{ "id":"…", "name":"…", "created_at":"2026-09-29T01:02:03Z", "last_used_at":null, "token":"mwk_…" }` |
| GET                | `/api/v1/tokens`                      | `{ "tokens":[…] }` ; apenas metadados                                                                                                  |
| DELETE             | `/api/v1/tokens/:id`                  | 204; revoga um token; repetir exclusão também retorna 204                                                                              |
| GET                | `/api/v1/mailboxes`                   | `{ "mailboxes":[…] }` ; visualizações de caixa de correio redigidas                                                                    |
| POST               | `/api/v1/mailboxes`                   | Crie com o formulário de caixa postal abaixo; 201, visualização redigida com `id` gerado e revisão 1                                   |
| GET / PUT / DELETE | `/api/v1/mailboxes/:id`               | Leitura/atualização com revisão/exclusão atual (204); ID ausente retorna 404 `mailbox_not_found`                                       |
| POST               | `/api/v1/mailboxes/test`              | Testar um formulário não salvo; retorna `{ "folders":[…] }` , mantém a configuração inalterada                                         |
| POST               | `/api/v1/mailboxes/:id/test`          | Teste o formulário com credenciais omitidas mescladas desta caixa de correio                                                           |
| GET                | `/api/v1/mailboxes/:id/folders`       | Descubra pastas selecionáveis usando o orçamento desta caixa de correio                                                                |
| GET / PUT          | `/api/v1/mailboxes/:id/subscriptions` | Ler/salvar assinaturas usando revisão própria; salvamento bem-sucedido retorna 202                                                     |
| GET / PUT          | `/api/v1/settings/delivery`           | Ler/salvar configurações de entrega global com sua própria revisão                                                                     |
| DELETE             | `/api/v1/settings/delivery`           | Limpe o canal e as credenciais salvos com `{revision}`; 204, revisão obsoleta 409                                                      |
| POST               | `/api/v1/settings/delivery/test`      | Teste o formulário de entrega com credenciais salvas mescladas; 204, configuração inalterada                                           |
| GET                | `/api/v1/status`                      | Estados da pasta, canal, contagens de entrega e avisos com escopo definido                                                             |
| GET                | `/api/v1/diagnostics`                 | Baixe um relatório JSON editado sem logs de tempo de execução                                                                          |
| GET                | `/api/v1/logs`                        | Logs operacionais autenticados; Filtros `after`, `level`, `mailbox_id`, `limit` (veja abaixo)                                          |
| GET                | `/api/v1/deliveries`                  | Últimos 50 registros de entrega, incluindo assunto e resumo de caixa de correio/pasta                                                  |
| POST               | `/api/v1/test-push`                   | Envie um teste usando configurações salvas; 204 quando aceito, configuração inalterada                                                 |
| POST               | `/api/v1/deliveries/:id/retry`        | Reenfileirar uma tarefa `dead`; 202                                                                                                    |

Os registros de entrega incluem um objeto `message` opcional: `mailbox_id` , `mailbox_label` , `folder` , `subject` (string ou nulo) e `test` (booleano). Os nomes são instantâneos do tempo de enfileiramento e sobrevivem à renomeação ou exclusão da caixa de correio. Um assunto nulo significa que não foi retido; uma string vazia significa que o e-mail não tinha assunto. As notificações de teste têm `test=true` e nenhuma origem de caixa de correio. A API omite o remetente e o corpo deste resumo.

Exemplo de criação de caixa postal:

```json
{
  "label": "Work mailbox",
  "host": "imap.example.org",
  "port": 993,
  "username": "user@example.org",
  "password": "…",
  "connection_limit": 10
}
```

O posto permite no máximo 20 caixas de correio salvas, incluindo configurações inválidas aguardando reparo; a próxima criação retorna 400 `mailbox_limit_exceeded` . Os IDs são gerados como `mbx_` mais uma sequência aleatória e permanecem estáveis. `label` usa como padrão o nome de usuário (endereço de e-mail), permite no máximo 64 caracteres Unicode e rejeita quebras de linha. Um nome de usuário com mais de 64 caracteres precisa de um rótulo explícito mais curto. Os rótulos omitidos na atualização mantêm o valor salvo; um rótulo vazio usa o nome de usuário enviado.

Caixa de correio PUT usa o mesmo formato mais `"revision":1` (o valor lido de GET ) e requer host, porta e nome de usuário. Se host, porta e nome de usuário não mudarem, omitir a senha mantém o valor salvo; uma senha vazia explícita é rejeitada. Omitido `connection_limit` mantém o valor atual; o padrão das novas caixas de correio é 10, intervalo de 2 a 100. A criação de POST omite a revisão ou envia 0. As rotas de teste aceitam os mesmos campos sem exigir revisão e mantêm a configuração inalterada. O teste não salvo requer credenciais; o teste de caixa de correio salva mescla credenciais omitidas somente do ID especificado.

Uma visualização da caixa de correio GET inclui `id` , `label` , `revision` , `host` , `port` , `username` , `connection_limit` , `connections_in_use` e `"password":{"configured":true}` . Uma caixa de correio inválida recuperada reporta `configured:false` e mantém seu ID e revisão para que possa ser reparada. O objeto de senha GET é uma visualização, não um valor de gravação válido.

Cada caixa de correio possui um orçamento de conexão independente. Cada pasta em tempo real consome um slot; todas as suas pastas agendadas juntas consomem uma. Sua demanda combinada deve caber em `connection_limit - 1`, reservando um slot para gerenciamento. As alterações na assinatura PUT e no limite da caixa de correio aplicam esta fórmula; capacidade esgotada retorna `connection_budget_exceeded` . Testar uma caixa de correio não salva utiliza um orçamento temporário. Os endpoints de teste não salvo, teste de caixa de correio salva e descoberta de pasta também compartilham um limite de simultaneidade global de 2; solicitações em excesso retornam 429 `discovery_busy` imediatamente. A conclusão ou cancelamento libera a admissão.

Exemplo de entrega PUT para um canal inicialmente não configurado:

```json
{
  "revision": 0,
  "channel": "bark",
  "preview": "off",
  "retry_count": 0,
  "language": "en",
  "bark": { "endpoint": "https://api.day.app", "key": "…" }
}
```

Leia `/settings/delivery` antes de cada atualização e envie sua revisão; o primeiro salvamento avança de 0 a 1. Pushover usa `"pushover":{"token":"…","user":"…"}` ; Webhook usa `"webhook":{"url":"https://hooks.example.org/mail","secret":"…"}` . Canal, visualização e revisão são necessários. O idioma omitido e a contagem de novas tentativas usam padrões. Se o destino não mudar, as credenciais omitidas, incluindo a URL do Webhook, mantêm os valores salvos; uma credencial ativa vazia explícita é rejeitada. GET substitui todas as credenciais por `{"configured":true|false}` . O endpoint de teste separado não requer revisão.

A caixa de correio cria e altera a conexão, testa a conexão/login antes de salvar. Se host, porta, nome de usuário e limite de conexão (connection_limit) corresponderem aos valores salvos e a senha for omitida, PUT altera apenas o rótulo: a verificação de revisão e a persistência ainda se aplicam, enquanto os testes e a substituição do inspetor são ignorados. As tarefas enfileiradas mantêm seu rótulo original; tarefas futuras usam o novo rótulo. Criar ou atualizar uma identidade já usada por outra caixa de correio retorna 409 `mailbox_duplicate` (host e nome de usuário são comparados sem distinção entre maiúsculas e minúsculas, porta exatamente); a criação simultânea pode salvar essa identidade apenas uma vez. A entrega PUT salva todos os canais após campo, endereço, estado de emparelhamento selecionado e validação de revisão, sem enviar teste ou entrar em contato com um provedor. Os testes de entrega explícita deixam as configurações salvas inalteradas; sua falha não bloqueia um salvamento posterior. Os testes de caixa de correio são executados fora dos bloqueios de configuração e mantêm os inspetores existentes ativos; um teste de caixa de correio com falha preserva sua configuração anterior. Revisões de configurações obsoletas retornam 409 `settings_conflict` ; uma alteração de assinatura durante um teste de caixa de correio também invalida o instantâneo desse teste. Recarregue antes de tentar novamente. Cada caixa de correio e as configurações de entrega global têm revisões independentes, portanto, as edições em caixas de correio diferentes ou em uma caixa de correio e entrega não entram em conflito.

Um PUT bem-sucedido retorna a visualização editada e aplica-se imediatamente. Uma alteração na conexão da caixa de correio interrompe seus próprios inspetores antes do salvamento e da redefinição opcional do cursor; uma falha no salvamento os restaura. Outras caixas de correio continuam em execução. As alterações na entrega preservam o instantâneo de uma tentativa em andamento; tentativas subsequentes usam o novo. As tarefas pendentes aguardam enquanto a entrega é desconfigurada.

`GET /api/v1/mailboxes/:id/subscriptions` retorna `{"revision":1,"folders":[{"name":"INBOX","check":"realtime"},{"name":"Clients","check":"5m"}]}` . PUT envia a leitura da revisão e o array `folders` completo; uma matriz vazia cancela a assinatura de tudo. Os nomes são exclusivos em cada caixa de correio, INBOX é normalizado e cada nome tem no máximo 4.096 bytes UTF-8. Cada pasta requer `name` e `check`; o cheque é `realtime` , `5m` ou `15m` . Verificações ausentes/inválidas e o formato de matriz de string anterior retornam 400. A fórmula de demanda de conexão acima substitui o limite de contagem de pastas. Alterar apenas a verificação preserva o progresso, recupera novos e-mails e mantém os IDs de eventos existentes; cancelar e depois assinar novamente cria uma nova linha de base. Todos os campos são obrigatórios. Salvar retorna 202 com a próxima revisão; revisões obsoletas retornam 409 `subscriptions_conflict` . A existência da pasta é confirmada pelo observador, portanto as assinaturas podem ser removidas enquanto a caixa de correio estiver offline. As falhas de armazenamento retornam 503 e preservam as assinaturas atuais.

Cada item `/status.folders[]` inclui `mailbox_id`, `mailbox_label` e `check`. `mode` é `idle`, `poll` ou `scheduled`; Pastas agendadas também incluem `next_check` (horário RFC 3339, incluindo tempos de repetição). Pastas em tempo real omitem `next_check` . A configuração salva que falha no JSON ou na validação do modelo torna-se desconfigurada, com `configuration_invalid` em `/status.notices` sob `mailbox:<id>` ou `delivery` ; PUT repara esse item. As assinaturas em excesso pausam apenas essa caixa de correio e reportam `connection_budget_exceeded` em `subscriptions:<id>` . Reduzir as assinaturas ou aumentar seu limite retoma o monitoramento. Falhas de descriptografia interrompem a inicialização.

A lista de permissões de diagnóstico contém tempo de geração, informações de construção/Go/plataforma, contagens de filas e estados anônimos de caixa de correio e inspetor, incluindo `check` e `mode` . `mailboxes[].index` e `watches[].mailbox_index` identificam “Caixa de correio 1”, “Caixa de correio 2” e assim por diante nesse relatório; os observadores de cada caixa de correio têm seu próprio `index` . As entradas da caixa de correio incluem códigos de aviso de configuração/assinatura. Somente `imap_folder_rejected` pode incluir `watches[].response_code` . O relatório omite IDs de caixas de correio, nomes de exibição, endereços, nomes de servidores, nomes de pastas, dados de mensagens, IDs de tarefas, credenciais e todos os outros parâmetros de erro.

A tarefa declara: `pending` aguarda uma solicitação, `accepted` significa que o canal aceitou a solicitação, `dead` significa que a tentativa terminou com uma falha registrada.

## Registros de tempo de execução

Use `docker compose logs -f core` (ou `docker logs <container>` ) para saída JSON stderr. Os clientes autenticados podem consultar os mesmos eventos operacionais por meio de `GET /api/v1/logs?after=0&level=info&mailbox_id=mbx_example&limit=200` . É necessário um cookie de sessão ou token de API.

O anel na memória mantém as entradas de Informações/Avisos/Erros mais recentes do **2000** e é limpo na reinicialização. `after` é uma sequência não negativa exclusiva; `level` seleciona esse nível e acima (padrão `info`); omitido `mailbox_id` inclui todas as caixas de correio e operações globais. O padrão de `limit` é 200, intervalo de 1 a 500. Parâmetros inválidos retornam 400 `logs_request_invalid` .

```json
{
  "entries": [
    {
      "seq": 42,
      "time": "2026-09-29T00:00:00Z",
      "level": "info",
      "message": "Folder connection established",
      "attrs": {
        "mailbox_id": "mbx_example",
        "folder": "INBOX",
        "mode": "idle",
        "check": "realtime"
      }
    }
  ],
  "next": 42,
  "cleared_through": 0
}
```

Use `next` como o `after` da próxima solicitação. No limite de páginas é a última sequência retornada; após a varredura do instantâneo, ele avança para a parte final do instantâneo, inclusive quando os filtros não correspondem a nada. As entradas despejadas são ignoradas. Se a reinicialização retornar `next < after` , redefina o cursor para 0. As entradas são ordenadas por sequência.
Os logs cobrem ciclos de vida de caixas de correio e pastas, contagens de linha de base/enfileiramento, tentativas de entrega, alterações de configuração e ações do administrador. Os eventos globais usam um `mailbox_id` vazio. Somente estes atributos escalares são expostos: `mailbox_id` , `folder` , `mode` , `check` , `code` , `event_id` , `channel` , `attempt` , `duration_ms` , `http_status`, `next_attempt`, `backoff_seconds`, `count`, `revision`, `token_id`, `version`, `listen`, `request_id`, `method`, `route`, `stage`, `outcome`, `cause_code`, `response_code`. `http_status=0` significa que nenhuma resposta HTTP foi recebida; `token_id` é um identificador de registro público, não o valor do token. Senhas, valores de token/sessão, códigos de configuração, remetente, assunto, corpos e URLs de credenciais são omitidos. A linha do código de configuração vai apenas para o console. Os logs contêm nomes de pastas; a exportação de diagnóstico anônimo exclui logs e nomes.

Os testes de descoberta de pasta e caixa de correio do administrador retornam `folders` como a matriz de caminho original mais `folder_roles` opcional, um mapa do caminho para `inbox` , `drafts` , `sent` , `trash` , `junk` , `archive`, `all` ou `flagged`. As funções vêm de atributos IMAP SPECIAL-USE; INBOX é reconhecido pelo seu nome definido pelo protocolo. A UI da Web recorre a correspondências exatas que não diferenciam maiúsculas de minúsculas para nomes de pastas comuns em inglês quando as funções estão ausentes. Os nomes traduzidos mostram o caminho original entre parênteses; outros nomes permanecem inalterados. As traduções de exibição nunca alteram os caminhos de assinatura. Os títulos de notificação usam o segmento final de caminhos de pasta separados por barras; os campos de pasta estruturados retêm o caminho completo. Os testes de caixa de correio do aplicativo continuam retornando apenas o status da conexão.

`GET /api/v1/session` inclui `username` para uma sessão de cookie autenticada. A autenticação de token mantém sua resposta existente.

### Dispositivo receptor de aplicativo

As configurações de entrega incluem `native_pairing_id` . Para o canal `native`, selecione um emparelhamento ativo de `/api/v1/native/devices` . Tanto as notificações de teste quanto os novos eventos visam apenas esse emparelhamento. A omissão do campo em uma atualização preserva a seleção salva; uma seleção vazia retorna `native_target_required` . Uma seleção indisponível retorna `native_target_unavailable` . A revogação do emparelhamento nativo selecionado limpa atomicamente o canal e o native_pairing_id e aumenta a revisão uma vez. Outros alvos e canais permanecem intactos. As entregas existentes mantêm seu objetivo e resultado de revogação. Consulte [sincronização de emparelhamento](https://github.com/mingzaily/mailwake/blob/main/docs/native-push.md#pairing-revocation-synchronization) para tempo, simultaneidade e comportamento de reinicialização.
A autorização do aplicativo gerencia a administração e envia permissões de forma independente. A revogação de uma das permissões deixa a outra inalterada.

### Notificações de teste nativo

O posto usa `POST /v1/pairing-tests` assinado com `{pairing_id,test_id}` (um UUID novo por teste explícito). O serviço de envio de notificações gera conteúdo fixo e o envia de forma síncrona aos APNs sem exigir o direito Native Push. Os testes de formulário, os testes de configuração salva do aplicativo e `/api/v1/test-push` usam o mesmo caminho. Os testes são separados da Caixa de saída de e-mail e não têm novas tentativas de entrega automática.

O posto retorna HTTP 204 somente quando o serviço de envio de notificações relata `accepted` . Rejeição de APNs, resultados desconhecidos e `sending` retornam um erro localizado; a limitação da taxa do serviço de envio de notificações faz com que o posto retorne HTTP 429 com `Retry-After` . Os logs seguros incluem o status HTTP do serviço de envio de notificações e o código de erro estável, excluindo corpos de resposta, tokens e conteúdo de notificação. O posto e o aplicativo compartilham as cotas diárias existentes por dispositivo e por minuto do serviço de envio de notificações e a idempotência `(device_id,test_id)`. Um usuário que inicia outro teste cria um novo ID de teste.

O correio formal usa `/v1/push` e permanece restrito a direitos, independentemente do ID do evento ou dos sinalizadores de teste do cliente. Implante a rota de teste de emparelhamento do serviço de envio de notificações antes desta versão do posto; o posto não recorre à entrega de correspondência paga.

## Limpar histórico de entrega e logs de tempo de execução

- `DELETE /api/v1/deliveries` retorna `200 {"deleted":N}` . Ele remove permanentemente os registros concluídos ( `accepted` / `dead` ) em todo o histórico, incluindo seus registros nativos associados. Entregas/novas tentativas pendentes, registros nativos ainda pendentes/em fila/envio ou agendados para verificações de status e atualizações de atividades nativas pendentes são retidos. A limpeza de falhas remove a opção de nova tentativa manual. Os pontos de verificação e a configuração da caixa de correio são preservados.
- `DELETE /api/v1/logs` retorna `200 {"cleared_through":N}` e limpa o anel de memória compartilhado para todos os níveis e caixas de correio. Os números de sequência continuam aumentando; Os logs stderr/container e os arquivos exportados permanecem. `GET /api/v1/logs` também retorna `cleared_through` ; os clientes descartam as entradas em cache com `seq <= cleared_through` antes de anexar as entradas retornadas.
- Ambos os terminais requerem sessão de administrador + Origin/CSRF ou um token de API de administrador. As credenciais do dispositivo de aplicativo não concedem essas operações. A compensação repetida é segura; novas entradas de trabalho e registro podem aparecer após a operação.

## Conteúdo da mensagem do aplicativo

`POST /api/v1/app/content` usa uma credencial de controlador vinculada ao dispositivo e a permissão `content` concedida pelo proprietário. Envie `{ "reference": <message_ref> }`; a resposta inclui `text`, `truncated`, `html` sanitizado opcional e `has_remote_images`. A leitura é gratuita.

Quando o corpo fica legível, `POST /api/v1/app/content/read` com a mesma credencial, permissão e referência marca a mensagem como lida na caixa de e-mail. O sucesso retorna `204 No Content` e `Cache-Control: no-store`. Apenas obter o conteúdo mantém o estado de leitura. Ambas as operações verificam a autorização atual, a pasta assinada, a identidade da caixa de e-mail e a referência da mensagem.

## Destino das credenciais

Ao testar ou salvar, alterar `host`, `port` ou `username` exige informar novamente a senha salva da caixa de correio; caso contrário, a resposta é 400 `mailbox_password_required_for_change`. Alterar o endereço Bark salvo exige a chave do dispositivo, mesmo com outro canal selecionado; caso contrário, a resposta é 400 `bark_key_required_for_change`. Porta, caminho e barra final fazem parte do endereço. Solicitações rejeitadas não abrem conexões e preservam a configuração e a revisão.

## Diagnóstico de solicitações do App

As exportações usam `schema_version: 2`. `app_requests` inclui até 300 solicitações recentes e concluídas do App, extraídas do log compartilhado de 2000 eventos em memória: horário, `request_id` gerado pelo servidor (também em `X-Request-ID`), modelo de rota, método, status HTTP, duração, etapa, resultado e códigos seguros. IDs de recursos, parâmetros de consulta, credenciais, referências assinadas, corpos e logs completos ficam excluídos. Reiniciar ou limpar os logs remove as entradas; outros eventos podem substituir as antigas. O download atualiza o relatório. Solicitações que não chegam ao servidor exigem diagnósticos do App.

`POST /api/v1/app/content/read` consulta UID e sinalizadores. Uma mensagem já lida tem sucesso; uma não lida é marcada e verificada novamente. STORE OK sozinho não comprova a existência. UID ausente, UIDVALIDITY alterado ou pasta explicitamente inexistente retornam 404; falhas do provedor ou de permissão, 503; tempo esgotado, 504. O corpo em cache permanece legível quando a referência remota expira.
