# Notifications

### Your notification feed, newest first

`GET /notifications`

**Parameters**

- `unread` _(query)_ · `"true" | "false"` · optional — Only unread when `true`.
- `cursor` _(query)_ · `string` · optional — Opaque cursor (page.nextCursor).
- `limit` _(query)_ · `number` · optional — Page size (1–100, default 20).

**Returns**

- `200` · `NotificationsPageDto`

Attributes of `NotificationsPageDto`:

- `data` · `object[]` · read-only
- `page` · `object` · read-only

**Example request**

```bash
curl https://api.koo.io/notifications \
  -H "Authorization: Bearer kc_your_api_token"
```

**Example response** (`200`)

```json
{
  "data": [
    {
      "id": "acct_01example0000000000000000x",
      "userId": "usr_01example0000000000000000x",
      "accountId": "acct_01example0000000000000000x",
      "kind": "example",
      "title": "example",
      "body": "example",
      "metadata": {
        "key": "example"
      },
      "readAt": "2026-01-01T00:00:00.000Z",
      "createdAt": "2026-01-01T00:00:00.000Z"
    }
  ],
  "page": {
    "nextCursor": "example",
    "hasMore": true
  }
}
```

### Your unread notification count

`GET /notifications/unread-count`

**Returns**

- `200` · `UnreadCountDto`

Attributes of `UnreadCountDto`:

- `count` · `integer` · read-only — Number of unread notifications.

**Example request**

```bash
curl https://api.koo.io/notifications/unread-count \
  -H "Authorization: Bearer kc_your_api_token"
```

**Example response** (`200`)

```json
{
  "count": 0
}
```

### Mark one notification read

`POST /notifications/{id}/read`

**Parameters**

- `id` _(path)_ · `string` · required

**Returns**

- `200` · `NotificationDto`
- `404` · `ErrorEnvelopeDto` — unknown id, or not your notification

Attributes of `NotificationDto`:

- `id` · `string` · read-only
- `userId` · `string` · read-only
- `accountId` · `string` · read-only
- `kind` · `string` · read-only
- `title` · `string` · read-only
- `body` · `string` · read-only
- `metadata` · `Record<string, string>` · read-only
- `readAt` · `string <date-time>` · read-only
- `createdAt` · `string <date-time>` · read-only

**Example request**

```bash
curl https://api.koo.io/notifications/:id/read \
  -X POST \
  -H "Authorization: Bearer kc_your_api_token"
```

**Example response** (`200`)

```json
{
  "id": "ntf_01example0000000000000000x",
  "userId": "usr_01example0000000000000000x",
  "accountId": "acct_01example0000000000000000x",
  "kind": "example",
  "title": "example",
  "body": "example",
  "metadata": {
    "key": "example"
  },
  "readAt": "2026-01-01T00:00:00.000Z",
  "createdAt": "2026-01-01T00:00:00.000Z"
}
```

### Mark every notification read

`POST /notifications/read-all`

**Returns**

- `200` · `UnreadCountDto`

Attributes of `UnreadCountDto`:

- `count` · `integer` · read-only — Number of unread notifications.

**Example request**

```bash
curl https://api.koo.io/notifications/read-all \
  -X POST \
  -H "Authorization: Bearer kc_your_api_token"
```

**Example response** (`200`)

```json
{
  "count": 0
}
```

### Your delivery preference for every notification kind (resolved)

`GET /me/notification-prefs`

**Returns**

- `200` · `NotificationPrefViewDto[]`

**Example request**

```bash
curl https://api.koo.io/me/notification-prefs \
  -H "Authorization: Bearer kc_your_api_token"
```

**Example response** (`200`)

```json
[
  {
    "kind": "example",
    "label": "example",
    "category": "deletion",
    "channel": "in_app",
    "frequency": "immediate",
    "forceEmail": true,
    "overridden": true
  }
]
```

### Set your delivery preference for one kind

`PUT /me/notification-prefs`

**Request body**

- `kind` · `string` · required
- `channel` · `"in_app" | "email" | "both" | "off"` · required
- `frequency` · `"immediate" | "daily" | "weekly"` · required

**Returns**

- `200` · `NotificationPrefViewDto`
- `422` · `ErrorEnvelopeDto` — unknown notification kind

Attributes of `NotificationPrefViewDto`:

- `kind` · `string` · read-only — Catalogue kind key, e.g. `deploy.ready`.
- `label` · `string` · read-only — Human label from the catalogue.
- `category` · `"deletion" | "billing" | "member" | "deploy" | "social"` · read-only
- `channel` · `"in_app" | "email" | "both" | "off"` · read-only
- `frequency` · `"immediate" | "daily" | "weekly"` · read-only
- `forceEmail` · `boolean` · read-only — Forced kinds (security/billing/deletion) are ALWAYS emailed regardless of the channel pref — the UI renders them locked.
- `overridden` · `boolean` · read-only — Whether the user stored an override for this kind.

**Example request**

```bash
curl https://api.koo.io/me/notification-prefs \
  -X PUT \
  -H "Authorization: Bearer kc_your_api_token" \
  -H "Content-Type: application/json" \
  -d '{
      "kind": "example",
      "channel": "in_app",
      "frequency": "immediate"
    }'
```

**Example response** (`200`)

```json
{
  "kind": "example",
  "label": "example",
  "category": "deletion",
  "channel": "in_app",
  "frequency": "immediate",
  "forceEmail": true,
  "overridden": true
}
```
