# Referencia de la API HTTP

## Idiomas y códigos de error

El inglés es el valor predeterminado. La API, la consola web y los renderizadores de notificaciones comparten los catálogos integrados en `internal/i18n/locales/`. `internal/i18n/languages.json` define estos códigos canónicos y nombres 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) |

- En la primera visita, la consola utiliza el `Accept-Language` del navegador. Su selector almacena localmente el código canónico elegido. Al cambiar el idioma de la consola, la configuración de notificaciones guardadas no cambia.
  Las solicitudes de API
- , incluidas las solicitudes de administración de aplicaciones, negocian `Accept-Language` por ponderaciones de calidad. Las respuestas incluyen `Content-Language` y `Vary: Accept-Language`. Se omiten las preferencias no admitidas; Las preferencias que faltan, no son válidas o no son totalmente compatibles se remontan a `en`. Un idioma con peso 0 queda excluido de la negociación.
- Las variantes regionales se asignan a su idioma admitido: `fr-CA` → `fr` , `es-MX` → `es` , `pt` / `pt-PT` → `pt-BR` . Se respeta la escritura china: `zh-Hans` / `zh-CN` / `zh-SG` → `zh-CN` ; `zh-Hant` / `zh-TW` / `zh-HK` / `zh-MO` → `zh-Hant`. Una secuencia de comandos explícita tiene prioridad sobre la región; El `zh` simple utiliza chino simplificado.
- `GET /locales/default.json` atiende el catálogo negociado; `GET /locales/{canonical-code}.json` sirve ese catálogo explícitamente. Las rutas de catálogo desconocidas devuelven `locale_not_supported`.
- Configuración de entrega `language` controla las notificaciones generadas por el puesto independientemente de la solicitud o el idioma de la consola. Acepta los códigos canónicos y las variantes regionales admitidas, conserva el código canónico y el valor predeterminado es `en` cuando se omite o está vacío. Un valor explícito no admitido devuelve 400 `config_language_invalid`.
- El servicio de envío de notificaciones genera un texto de notificación de prueba nativo utilizando el idioma del dispositivo emparejado. El idioma de notificación del puesto no anula ese idioma. El servicio de envío de notificaciones y la aplicación admiten cada uno su propio conjunto de idiomas.
- Las funciones de carpeta estándar y los nombres de carpeta comunes están localizados en la consola. Las rutas IMAP sin procesar, los nombres personalizados y `folder_roles` permanecen sin cambios en las API; Las aplicaciones localizan estos roles con sus propios catálogos. Los títulos de notificaciones continúan usando el nombre de la carpeta hoja original. Los nombres ingresados por el usuario, los asuntos de los correos electrónicos, el contenido de los correos electrónicos y los códigos de verificación siguen siendo literales.
- Los registros y la salida CLI utilizan el inglés. Los errores comerciales conservan códigos `snake_case` en inglés estables y parámetros con nombre; el almacenamiento guarda códigos y parámetros, y las capas de visualización traducen mensajes. Las fechas y números en las respuestas de API mantienen sus formatos legibles por máquina existentes; la consola formatea las marcas de tiempo utilizando la configuración regional elegida.

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

`last_error` en registros de entrega y `notice` en estado de carpeta usan la misma forma `{code, message, params?}`, por ejemplo `bark_http_error` con `{"status":"503"}`. Sucursal en `code`; mostrar `message`.

Cada buzón reserva una conexión para el descubrimiento de carpetas y las pruebas de conexión. La demanda de Watcher es `realtime Folder count + (1 if any scheduled Folders exist, otherwise 0)`, como máximo conexiones `connection_limit - 1` (9 por defecto); todas las operaciones para ese buzón juntas permanecen dentro de `connection_limit` (2–100). Las configuraciones guardadas con un límite de 1 inician en modo de recuperación con `configuration_invalid`.

## API HTTP

`GET /` sirve la página actual; Los activos estáticos y `/healthz` son públicos. Antes de la configuración, todos los demás puntos finales de administración devuelven 403 `setup_required`. `POST /api/v1/setup` está disponible una vez; `POST /api/v1/session` es público después de la configuración. Todas las API restantes requieren la cookie de sesión o `Authorization: Bearer mwk_…`.

Las sesiones de cookies utilizan HttpOnly, SameSite=Strict, Path=/, Secure en una conexión TLS o un origen HTTPS, un tiempo de espera de inactividad de siete días y un tiempo de espera absoluto de 30 días. Cada mutación autenticada por cookie requiere `X-CSRF-Token` y un HTTP(S) `Origin` cuyo host y puerto opcional coincidan exactamente con el Host de solicitud. Las solicitudes con Bearer omiten las comprobaciones CSRF. Un encabezado de Autorización no válido falla incluso cuando hay una cookie válida presente.
Las fallas del código de inicio de sesión y configuración de comparten un presupuesto de dirección de origen: diez fallas cada 15 minutos, seguidas de 429 `too_many_attempts` con `Retry-After` en segundos. La fuente es Gin ClientIP que utiliza los rangos de proxy confiables anteriores. Los cambios de contraseña también utilizan este presupuesto. Los orígenes explícitos entre sitios se rechazan al iniciar sesión y configurar. Debido a que se confía en cada par de la red privada como proxy, un cliente en su red local puede configurar X-Forwarded-For y distribuir sus intentos entre muchas direcciones de origen. No exponga al puerto de escucha del puesto a una red local que no sea de confianza; publíquelo únicamente a través de su proxy inverso.

Todos los cuerpos JSON están limitados a 64 KiB; Los campos desconocidos o JSON final devuelven 400. Las contraseñas tienen un mínimo de 12 caracteres y un máximo de 1024 UTF-8 bytes. Los nombres de usuario y los nombres de tokens tienen entre 1 y 128 bytes. Todas las marcas de tiempo de la API de administración son cadenas RFC 3339 en UTC, incluida la entrega `created_at`/`accepted_at`, el token `created_at`/`last_used_at`, las comprobaciones de carpetas, los tiempos de registro y el tiempo de generación de diagnóstico. Las fracciones de segundo preservan la precisión almacenada. El token no utilizado `last_used_at` es nulo; las entregas sin aceptación omiten `accepted_at`. Los recuentos, duraciones y revisiones siguen siendo números.

401 identifica una sesión o token de API no válido, o credenciales rechazadas en `POST /api/v1/session`. Un código de configuración incorrecto devuelve 400 `setup_code_invalid`; el asistente regresa al paso del código y conserva el nombre de usuario. Una contraseña actual incorrecta en `PUT /api/v1/admin/password` devuelve 400 `current_password_invalid` y cuenta para el límite de fallas; la sesión actual sigue siendo válida. Los errores de inicio de sesión y los errores de contraseña actual aparecen dentro del formulario, preservando sus entradas.

| Método             | Ruta                                  | Solicitud / respuesta                                                                                                                 |
| ------------------ | ------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
| POST               | `/api/v1/setup`                       | `{ "code":"XXXX-XXXX-XXXX", "username":"admin", "password":"…" }` ; 201, cookie + `{ "csrf_token":"…" }`; repetir configuración: 409  |
| POST               | `/api/v1/session`                     | `{ "username":"admin", "password":"…" }` ; 200, cookie + token CSRF                                                                   |
| GET                | `/api/v1/session`                     | `{ "authenticated":true, "csrf_token":"…" }` ; Bearer devuelve `method: "token"` en lugar de CSRF                                     |
| DELETE             | `/api/v1/session`                     | 204; revoca la sesión de cookies actual; requiere una sesión                                                                          |
| PUT                | `/api/v1/admin/password`              | `{ "current_password":"…", "password":"…" }` ; 204, revoca otras sesiones; Bearer revoca todas las sesiones                           |
| 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":[…] }` ; solo metadatos                                                                                                   |
| DELETE             | `/api/v1/tokens/:id`                  | 204; revoca una ficha; la eliminación repetida también devuelve 204                                                                   |
| GET                | `/api/v1/mailboxes`                   | `{ "mailboxes":[…] }` ; vistas de buzón redactadas                                                                                    |
| POST               | `/api/v1/mailboxes`                   | Crear con el formulario de buzón a continuación; 201, vista redactada con `id` generado y revisión 1                                  |
| GET / PUT / DELETE | `/api/v1/mailboxes/:id`               | Leer/actualizar con revisión actual/eliminar (204); ID faltante devuelve 404 `mailbox_not_found`                                      |
| POST               | `/api/v1/mailboxes/test`              | Probar un formulario no guardado; devuelve `{ "folders":[…] }`, mantiene la configuración sin cambios                                 |
| POST               | `/api/v1/mailboxes/:id/test`          | Pruebe el formulario con credenciales omitidas fusionadas desde este buzón                                                            |
| GET                | `/api/v1/mailboxes/:id/folders`       | Descubra carpetas seleccionables utilizando el presupuesto de este buzón                                                              |
| GET / PUT          | `/api/v1/mailboxes/:id/subscriptions` | Leer/guardar suscripciones utilizando su propia revisión; devoluciones guardadas exitosas 202                                         |
| GET / PUT          | `/api/v1/settings/delivery`           | Leer/guardar la configuración de entrega global con su propia revisión                                                                |
| DELETE             | `/api/v1/settings/delivery`           | Borre el canal guardado y las credenciales con `{revision}`; 204, revisión obsoleta 409                                               |
| POST               | `/api/v1/settings/delivery/test`      | Pruebe el formulario de entrega con las credenciales guardadas fusionadas; 204, configuración sin cambios                             |
| GET                | `/api/v1/status`                      | Estados de carpeta, canal, recuentos de entrega y avisos de alcance                                                                   |
| GET                | `/api/v1/diagnostics`                 | Descargue un informe JSON redactado sin registros de tiempo de ejecución                                                              |
| GET                | `/api/v1/logs`                        | Registros operativos autenticados; Filtros `after`, `level`, `mailbox_id`, `limit` (ver más abajo)                                    |
| GET                | `/api/v1/deliveries`                  | Últimos 50 registros de entrega, incluido el asunto y el resumen del buzón/carpeta                                                    |
| POST               | `/api/v1/test-push`                   | Enviar una prueba utilizando la configuración guardada; 204 cuando se acepta, configuración sin cambios                               |
| POST               | `/api/v1/deliveries/:id/retry`        | Poner en cola una tarea `dead`; 202                                                                                                   |

Los registros de entrega incluyen un objeto `message` opcional: `mailbox_id`, `mailbox_label`, `folder`, `subject` (cadena o nulo) y `test` (booleano). Los nombres son instantáneas del tiempo de puesta en cola y sobreviven al cambio de nombre o la eliminación del buzón. Un asunto nulo significa que no fue retenido; una cadena vacía significa que el correo no tenía asunto. Las notificaciones de prueba tienen `test=true` y no tienen origen de buzón. La API omite el remitente y el cuerpo de este resumen.

Ejemplo de creación de buzón:

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

El puesto permite guardar como máximo 20 buzones de correo, incluidas configuraciones no válidas en espera de reparación; la próxima creación devuelve 400 `mailbox_limit_exceeded`. Los ID se generan como `mbx_` más una cadena aleatoria y permanecen estables. `label` utiliza de forma predeterminada el nombre de usuario (dirección de correo electrónico), permite como máximo 64 caracteres Unicode y rechaza los saltos de línea. Un nombre de usuario de más de 64 caracteres necesita una etiqueta más corta explícita. Las etiquetas omitidas durante la actualización mantienen el valor guardado; una etiqueta vacía utiliza el nombre de usuario enviado.

El buzón de correo PUT usa el mismo formulario más `"revision":1` (el valor leído de GET) y requiere host, puerto y nombre de usuario. Si host, puerto y nombre de usuario no cambian, omitir la contraseña conserva la guardada; se rechaza una contraseña vacía explícita. Omitido `connection_limit` mantiene el valor actual; Los nuevos buzones de correo tienen un valor predeterminado de 10, rango de 2 a 100. La creación de POST omite la revisión o envía 0. Las rutas de prueba aceptan los mismos campos sin requerir una revisión y mantienen la configuración sin cambios. La prueba no guardada requiere credenciales; la prueba del buzón guardado combina las credenciales omitidas solo del ID especificado.

Una vista de buzón GET incluye `id`, `label`, `revision`, `host`, `port`, `username`, `connection_limit`, `connections_in_use` y `"password":{"configured":true}`. Un buzón de correo no válido recuperado informa `configured:false` y conserva su ID y revisión para que pueda repararse. El objeto de contraseña GET es una vista, no un valor de escritura válido.

Cada buzón tiene un presupuesto de conexión independiente. Las carpetas en tiempo real consumen cada una una ranura; todas sus carpetas programadas juntas consumen una. Su demanda combinada debe caber dentro de `connection_limit - 1`, reservando un espacio para la gestión. La suscripción PUT y los cambios en el límite del buzón hacen cumplir esta fórmula; capacidad agotada regresa `connection_budget_exceeded`. Para probar un buzón de correo no guardado se utiliza un presupuesto temporal. Los puntos finales de prueba no guardada, prueba de buzón guardado y descubrimiento de carpetas comparten además un límite de simultaneidad global de 2; Las solicitudes excedentes devuelven 429 `discovery_busy` inmediatamente. La finalización o cancelación libera la admisión.

Ejemplo de entrega PUT para un canal inicialmente no configurado:

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

Leer `/settings/delivery` antes de cada actualización y enviar su revisión; el primer guardado avanza de 0 a 1. Pushover usa `"pushover":{"token":"…","user":"…"}`; El webhook utiliza `"webhook":{"url":"https://hooks.example.org/mail","secret":"…"}`. Se requiere canal, vista previa y revisión. El idioma omitido y el recuento de reintentos utilizan los valores predeterminados. Si el destino no cambia, las credenciales omitidas, incluida la URL del Webhook, mantienen los valores guardados; se rechaza una credencial activa vacía explícita. GET reemplaza cada credencial con `{"configured":true|false}`. El criterio de valoración de prueba independiente no requiere revisión.

El buzón se crea y la conexión cambia, prueba la conexión/inicio de sesión antes de guardar. Si el host, el puerto, el nombre de usuario y el límite de conexión (connection_limit) coinciden con los valores guardados y se omite la contraseña, PUT cambia solo la etiqueta: la verificación de revisión y la persistencia aún se aplican, mientras que las pruebas y el reemplazo del observador se omiten. Las tareas en cola conservan su etiqueta original; Las tareas futuras utilizan la nueva etiqueta. Crear o actualizar una identidad ya utilizada por otro buzón devuelve 409 `mailbox_duplicate` (el host y el nombre de usuario se comparan sin distinguir entre mayúsculas y minúsculas, puerto exacto); la creación concurrente puede salvar esa identidad solo una vez. La entrega PUT guarda todos los canales después del campo, la dirección, el estado de emparejamiento seleccionado y la validación de revisión, sin enviar una prueba ni contactar a un proveedor. Las pruebas de entrega explícitas dejan la configuración guardada sin cambios; su fallo no bloquea una salvación posterior. Las pruebas de buzón se ejecutan fuera de los bloqueos de configuración y mantienen activos a los observadores existentes; una prueba de buzón fallida conserva su configuración anterior. Las revisiones de configuraciones obsoletas devuelven 409 `settings_conflict`; un cambio de suscripción durante una prueba de buzón también invalida la instantánea de esa prueba. Vuelva a cargar antes de volver a intentarlo. Cada buzón y la configuración de entrega global tienen revisiones independientes, por lo que las ediciones en diferentes buzones o en un buzón y la entrega no entran en conflicto.

Un PUT correcto devuelve la vista redactada y se aplica inmediatamente. Un cambio de conexión de buzón detiene a sus propios observadores antes de guardar y restablecer el cursor opcional; un guardado fallido los restaura. Otros buzones continúan ejecutándose. Los cambios de entrega conservan la instantánea de un intento en vuelo; Los intentos posteriores utilizan el nuevo. Las tareas pendientes esperan mientras se desconfigura la entrega.

`GET /api/v1/mailboxes/:id/subscriptions` devuelve `{"revision":1,"folders":[{"name":"INBOX","check":"realtime"},{"name":"Clients","check":"5m"}]}`. PUT envía la lectura de revisión y el array completo de `folders`; una matriz vacía se da de baja de todo. Los nombres son únicos dentro de cada buzón, INBOX está normalizado y cada nombre tiene como máximo 4096 bytes UTF-8. Cada carpeta requiere `name` y `check`; La verificación es `realtime`, `5m` o `15m`. Las comprobaciones faltantes/no válidas y el formato de matriz de cadenas anterior devuelven 400. La fórmula de demanda de conexión anterior reemplaza el límite de recuento de carpetas. Cambiar solo la verificación preserva el progreso, se pone al día con el correo nuevo y mantiene las ID de eventos existentes; cancelar y luego suscribirse nuevamente crea una nueva base de referencia. Todos los campos son obligatorios. Guardar devuelve 202 con la próxima revisión; revisiones obsoletas devuelven 409 `subscriptions_conflict`. El observador confirma la existencia de la carpeta, por lo que las suscripciones se pueden eliminar mientras el buzón está fuera de línea. Los errores de almacenamiento devuelven 503 y preservan las suscripciones actuales.

Cada artículo `/status.folders[]` incluye `mailbox_id`, `mailbox_label` y `check`. `mode` es `idle`, `poll` o `scheduled`; Las carpetas programadas también incluyen `next_check` (hora RFC 3339, incluidos los tiempos de reintento). Las carpetas en tiempo real omiten `next_check`. La configuración guardada que falla en JSON o en la validación del modelo se desconfigura, con `configuration_invalid` en `/status.notices` en `mailbox:<id>` o `delivery`; PUT repara ese artículo. El exceso de suscripciones pausa solo ese buzón e informa `connection_budget_exceeded` en `subscriptions:<id>`. Reducir las suscripciones o aumentar su límite reanuda el seguimiento. Los errores de descifrado detienen el inicio.

La lista de diagnósticos permitidos contiene tiempo de generación, información de compilación/Ir/plataforma, recuentos de colas y estados de vigilancia y buzones de correo anónimos, incluidos `check` y `mode`. `mailboxes[].index` y `watches[].mailbox_index` identifican “Buzón 1”, “Buzón 2”, etc. dentro de ese informe; Los vigilantes de cada buzón tienen su propio `index`. Las entradas del buzón incluyen códigos de aviso de configuración/suscripción. Sólo `imap_folder_rejected` puede incluir `watches[].response_code`. El informe omite los ID de los buzones de correo, los nombres para mostrar, las direcciones, los nombres de los servidores, los nombres de las carpetas, los datos de los mensajes, los ID de las tareas, las credenciales y todos los demás parámetros de error.

Estados de la tarea: `pending` espera una solicitud, `accepted` significa que el canal aceptó la solicitud, `dead` significa que el intento finalizó con un error registrado.

## Registros de tiempo de ejecución

Utilice `docker compose logs -f core` (o `docker logs <container>`) para la salida estándar JSON. Los clientes autenticados pueden consultar los mismos eventos operativos a través de `GET /api/v1/logs?after=0&level=info&mailbox_id=mbx_example&limit=200`. Se requiere una cookie de sesión o un token API.

El anillo en memoria mantiene las entradas de información/advertencia/error **2000** más recientes y se borra al reiniciar. `after` es una secuencia no negativa exclusiva; `level` selecciona ese nivel y superiores (valor predeterminado: `info`); omitido `mailbox_id` incluye todos los buzones y operaciones globales. `limit` tiene como valor predeterminado 200, rango 1–500. Los parámetros no válidos devuelven 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
}
```

Utilice `next` como `after` de la siguiente solicitud. En el límite de páginas, es la última secuencia devuelta; después de escanear la instantánea, avanza a la cola de la instantánea, incluso cuando los filtros no coinciden. Se omiten las entradas desalojadas. Si el reinicio devuelve `next < after`, restablezca el cursor a 0. Las entradas están ordenadas por secuencia.

Los registros cubren los ciclos de vida de buzones y carpetas, recuentos de líneas base/en cola, intentos de entrega, cambios de configuración y acciones del administrador. Los eventos globales utilizan un `mailbox_id` vacío. Solo se exponen estos atributos escalares: `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 no se recibió ninguna respuesta HTTP; `token_id` es un identificador de registro público, no el valor del token. Se omiten las contraseñas, los valores de token/sesión, los códigos de configuración, el remitente, el asunto, los cuerpos y las URL de credenciales. La línea del código de configuración va sólo a la consola. Los registros contienen nombres de carpetas; la exportación de diagnóstico anónimo excluye registros y nombres.

Las pruebas de buzón de administrador y descubrimiento de carpetas devuelven `folders` como la matriz de ruta original más `folder_roles` opcional, un mapa de la ruta a `inbox`, `drafts`, `sent`, `trash`, `junk`, `archive`, `all` o `flagged`. Los roles provienen de atributos IMAP de USO ESPECIAL; INBOX se reconoce por su nombre definido por el protocolo. La interfaz de usuario web recurre a coincidencias exactas que no distinguen entre mayúsculas y minúsculas para nombres de carpetas comunes en inglés cuando no hay roles. Los nombres traducidos muestran la ruta original entre paréntesis; otros nombres permanecen sin cambios. Las traducciones en pantalla nunca cambian las rutas de suscripción. Los títulos de las notificaciones utilizan el segmento final de rutas de carpetas separadas por barras diagonales; Los campos de carpetas estructuradas conservan la ruta completa. Las pruebas del buzón de la aplicación continúan arrojando solo el estado de la conexión.

`GET /api/v1/session` incluye `username` para una sesión de cookies autenticada. La autenticación de token mantiene su respuesta existente.

### Dispositivo receptor de aplicaciones

La configuración de entrega incluye `native_pairing_id`. Para el canal `native`, seleccione un emparejamiento activo de `/api/v1/native/devices`. Tanto las notificaciones de prueba como los eventos nuevos se dirigen únicamente a ese emparejamiento. Omitir el campo en una actualización conserva la selección guardada; una selección vacía devuelve `native_target_required`. Una selección no disponible devuelve `native_target_unavailable`. Revocar el emparejamiento nativo seleccionado borra atómicamente el canal y el native_pairing_id e incrementa la revisión una vez. Otros objetivos y canales permanecen intactos. Las entregas existentes conservan su destino y resultado de revocación. Consulte [sincronización de emparejamiento](https://github.com/mingzaily/mailwake/blob/main/docs/native-push.md#pairing-revocation-synchronization) para conocer el comportamiento de sincronización, simultaneidad y reinicio.

La autorización de la aplicación gestiona la administración y los permisos de inserción de forma independiente. Revocar cualquiera de los permisos deja el otro sin cambios.

### Notificaciones de prueba nativas

El puesto utiliza `POST /v1/pairing-tests` firmado con `{pairing_id,test_id}` (un UUID nuevo por prueba explícita). El servicio de envío de notificaciones genera contenido fijo y lo envía sincrónicamente a las APNs sin requerir el derecho de Native Push. Las pruebas de formulario, las pruebas de configuración guardada de la aplicación y `/api/v1/test-push` utilizan esta misma ruta. Las pruebas están separadas de la bandeja de salida del correo y no tienen reintentos de entrega automáticos.

El puesto devuelve HTTP 204 solo cuando el servicio de envío de notificaciones informa `accepted`. El rechazo de APNs, los resultados desconocidos y `sending` devuelven un error localizado; la limitación de la tasa del servicio de envío de notificaciones hace que el puesto devuelva HTTP 429 con `Retry-After`. Los registros seguros incluyen el estado HTTP del servicio de envío de notificaciones y el código de error estable, excluyendo los cuerpos de respuesta, los tokens y el contenido de las notificaciones. El puesto y la aplicación comparten las cuotas diarias por minuto y por sujeto existentes del servicio de envío de notificaciones y la idempotencia `(device_id,test_id)`. Un usuario que inicia otra prueba crea una nueva ID de prueba.

El correo formal utiliza `/v1/push` y permanece controlado por derechos independientemente del ID del evento o los indicadores de prueba del cliente. Implementar la ruta de prueba de emparejamiento del servicio de envío de notificaciones antes de esta versión avanzada; el puesto no recurre a la entrega de correo pagado.

## Borrar historial de entrega y registros de tiempo de ejecución

- `DELETE /api/v1/deliveries` devuelve `200 {"deleted":N}`. Elimina permanentemente los registros terminados ( `accepted` / `dead` ) de todo el historial, incluidos sus registros nativos asociados. Se conservan las entregas/reintentos pendientes, los registros nativos aún pendientes/en cola/enviando o programados para verificaciones de estado y las actualizaciones de actividad nativa pendientes. Al borrar los errores se elimina la opción de reintento manual. Se conservan los puntos de control y la configuración del buzón.
- `DELETE /api/v1/logs` devuelve `200 {"cleared_through":N}` y borra el anillo en memoria compartido para todos los niveles y buzones. Los números de secuencia continúan aumentando; Los registros de stderr/container y los archivos exportados permanecen. `GET /api/v1/logs` también devuelve `cleared_through`; Los clientes descartan las entradas almacenadas en caché con `seq <= cleared_through` antes de agregar las entradas devueltas.
- Ambos puntos finales requieren sesión de administrador + Origen/CSRF, o un token de API de administrador. Las credenciales del dispositivo de la aplicación no permiten estas operaciones. La limpieza repetida es segura; Es posible que aparezcan nuevas entradas de trabajo y registro después de la operación.

## Contenido del mensaje de la aplicación

`POST /api/v1/app/content` usa una credencial de controlador vinculada al dispositivo y el permiso `content` concedido por el propietario. Envía `{ "reference": <message_ref> }`; la respuesta incluye `text`, `truncated`, `html` saneado opcional y `has_remote_images`. La lectura es gratuita.

Cuando el cuerpo es legible, `POST /api/v1/app/content/read` con la misma credencial, permiso y referencia marca el mensaje como leído en el buzón. El éxito devuelve `204 No Content` y `Cache-Control: no-store`. Obtener solo el contenido conserva el estado de lectura. Ambas operaciones verifican la autorización actual, la carpeta suscrita, la identidad del buzón y la referencia del mensaje.

## Destino de las credenciales

Al probar o guardar, cambiar `host`, `port` o `username` exige volver a introducir la contraseña guardada; de lo contrario, se devuelve 400 `mailbox_password_required_for_change`. Cambiar la dirección de Bark guardada exige su clave de dispositivo, incluso con otro canal seleccionado; de lo contrario, se devuelve 400 `bark_key_required_for_change`. El puerto, la ruta y la barra final forman parte de la dirección. Las solicitudes rechazadas no abren conexiones y conservan la configuración y la revisión.

## Diagnóstico de solicitudes de la App

Las exportaciones usan `schema_version: 2`. `app_requests` incluye hasta 300 solicitudes recientes y finalizadas de la App, tomadas del registro compartido de 2000 eventos en memoria: hora, `request_id` generado por el servidor (también en `X-Request-ID`), plantilla de ruta, método, estado HTTP, duración, etapa, resultado y códigos seguros. Se excluyen identificadores de recursos, parámetros de consulta, credenciales, referencias firmadas, cuerpos y registros completos. Reiniciar o borrar los registros elimina estas entradas; otros eventos pueden desplazar las antiguas. La descarga actualiza el informe. Las solicitudes que no llegan al servidor requieren diagnósticos de la App.

`POST /api/v1/app/content/read` consulta UID y marcas. Un mensaje ya leído tiene éxito; uno sin leer se marca y se verifica de nuevo. STORE OK por sí solo no prueba su existencia. UID ausente, UIDVALIDITY cambiado o carpeta explícitamente inexistente devuelven 404; fallos del proveedor o permisos, 503; tiempo agotado, 504. El cuerpo en caché sigue disponible si caduca la referencia remota.
