# API de notificaciones

> Lista la bandeja de notificaciones del usuario de sesión y marca filas como leídas.

Probara expone dos endpoints para la bandeja de notificaciones del usuario de
sesión: un listado paginado por cursor y una acción de marcar-leído. Ambos
requieren una sesión autenticada — inicia sesión en el navegador y envía la
cookie de sesión más `X-Organization-Id` al llamar desde scripts propios.
Ambos están limitados a la organización activa; no existe una superficie de
token de portador (API token) para notificaciones.

## Listar notificaciones

`GET /api/v1/notifications`

Devuelve la bandeja del usuario de sesión para la organización activa, de más
reciente a más antigua.

### Parámetros de consulta

| Parámetro    | Tipo    | Notas                                                                                                                                    |
| ------------ | ------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| `cursor`     | ULID    | Cuando se envía, devuelve filas posteriores a este cursor (página más antigua)                                                           |
| `limit`      | integer | Tamaño de página. Por defecto `20`. `0` es un valor explícito válido. Valores mayores a `100` son rechazados con `422 validation_failed` |
| `unreadOnly` | boolean | `true` devuelve solo las filas no leídas                                                                                                 |

### Forma de la respuesta

```json
{
  "items": [
    {
      "ulid": "01J…",
      "kind": "defect.assigned",
      "entityType": "defect",
      "entityUlid": "01J…",
      "actorLabel": "María López",
      "actorAvatarKey": "avatars/users/01J….webp",
      "actorAvatarVersion": 2,
      "eventCount": 1,
      "createdAt": 1700000000000,
      "readAt": null,
      "payload": { "entity": { "title": "Login regression", "url": "/x" } }
    }
  ],
  "nextCursor": "01J…",
  "unreadCount": 4
}
```

`unreadCount` refleja los mismos filtros de autorización y estado de lectura
que `items`, así que ambos nunca pueden discrepar — no es una consulta
separada.

### Tipos

`kind` es una de las filas del catálogo de notificaciones; `entityType` y `entityUlid` indican sobre
qué trata la notificación, y `payload.entity.url` enlaza a ello en la app.

| `kind`                                                                                                                                                     | `entityType`       |
| ---------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------ |
| `test_case.comment_created`, `test_case.comment_mention`                                                                                                   | `test_case`        |
| `test_plan.case_assigned`                                                                                                                                  | `test_plan`        |
| `test_run.created_as_default_assignee`, `test_run.case_assigned`, `test_run.closed_or_aborted`                                                             | `test_run`         |
| `defect.assigned`, `defect.comment_created`, `defect.comment_mention`, `defect.status_changed`                                                             | `defect`           |
| `test_case_review.assigned`, `test_case_review.decided`, `test_case_review.edited`, `test_case_review.comment_created`, `test_case_review.comment_mention` | `test_case_review` |

Una fila `test_case_review.decided` lleva la decisión en `payload.context.status`: `approved`,
`changes_requested`, `declined` o `merged`. En una notificación de revisión,
`payload.entity.displayId` es el ID `RV-` de la solicitud.

Una acción masiva de revisión (enviar varios casos a revisión, o una decisión sobre varias
solicitudes) envía una fila `test_case_review.assigned` o `test_case_review.decided` por
destinatario con `entityType` `test_case_review_batch`: `eventCount` es cuántas solicitudes del lote
le conciernen, `payload.entity.title` es el nombre del proyecto y `payload.entity.url` abre la lista
de Revisión.

### Ejemplo

```bash
curl -sS \
  -H "Cookie: $PROBARA_SESSION_COOKIE" \
  -H "X-Organization-Id: $ORG_ULID" \
  "https://app.probara.net/api/v1/notifications?limit=20&unreadOnly=true"
```

## Marcar notificaciones como leídas

`POST /api/v1/notifications/read`

### Cuerpo de la solicitud

| Campo   | Requerido | Notas                                                                                                                                                                                                                 |
| ------- | --------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `ulids` | no        | Array de ULIDs de notificaciones a marcar como leídas, limitado a las filas propias del solicitante sin importar el valor. Omitirlo o enviarlo vacío marca como leída cada fila visible. **Como máximo 200 entradas** |

### Límites de solicitud

`ulids` tiene un límite de **200 entradas** — un techo contra abuso, no un
techo de producto. Enviar más de 200 responde `422 validation_failed`
nombrando el campo `ulids`; ninguna fila cambia su estado de lectura y el
contador de no leídas queda sin cambios.

Omitir `ulids` por completo no se ve afectado por este límite: conserva su
significado ya publicado de marcar-todo-lo-visible.

### Respuesta

`204 No Content` en éxito. Marcar una fila ya leída (o repetir la misma
solicitud) es una operación sin efecto.

### Ejemplo — marcar como leídas todas las filas visibles

```bash
curl -sS -X POST \
  -H "Cookie: $PROBARA_SESSION_COOKIE" \
  -H "X-Organization-Id: $ORG_ULID" \
  -H "Content-Type: application/json" \
  --data-raw '{}' \
  "https://app.probara.net/api/v1/notifications/read"
```

### Ejemplo — marcar filas específicas como leídas

```bash
curl -sS -X POST \
  -H "Cookie: $PROBARA_SESSION_COOKIE" \
  -H "X-Organization-Id: $ORG_ULID" \
  -H "Content-Type: application/json" \
  -d '{"ulids": ["01J...A", "01J...B"]}' \
  "https://app.probara.net/api/v1/notifications/read"
```

## Relacionado

- [Referencia API](https://docs.probara.net/es/developers/api-reference/) — paginación, errores, autenticación
- [Referencia interactiva v1](https://docs.probara.net/es/developers/api-reference/v1/) — esquemas completos
- [API de eventos de auditoría](https://docs.probara.net/es/developers/api/audit-events/) — el feed de actividad de toda la organización
