VitrinaAPI

My notifications

What the caller sees: the notification feed for the active workspace and their notification preferences, by preset or cell by cell.

Beta
This may change at any time, with a changelog entry and a notice to recent callers — see versioning.

Download the full API pública projection: openapi.json.

MethodPathWhat it does
GET/me/notification-preferencesThe caller’s notification preferences, generated from the registry
PUT/me/notification-preferencesChange notification preferences (preset and/or single cells)
GET/me/notificationsIn-app notification feed for the active workspace (keyset-paginated)

GET /me/notification-preferences

The caller’s notification preferences, generated from the registry

Every notification type this member can receive in this workspace (filtered by role and vertical), grouped by category, with the state of each channel — bell (in_app), email, push, whatsapp: on/off (their choice, or the default when they never chose), locked (mandatory, with locked_reason), always (the bell of a type they must act on) or unavailable. WhatsApp is available only for types the workspace armed for staff WhatsApp. preset is important (the defaults), all or custom. Requires a workspace member; an sk_* API key gets 403.

curl https://api.vitrinadev.com/api/v1/me/notification-preferences \
  -H "Authorization: Bearer $VITRINA_KEY"

Example response (200)

{
  "data": {
    "preset": "important",
    "push_enabled": true,
    "categories": [
      "inbox",
      "agenda",
      "sales",
      "followups",
      "approvals",
      "payments",
      "agents",
      "integrations",
      "safety",
      "account"
    ],
    "types": [
      {
        "key": "assigned",
        "category": "inbox",
        "slug": "assigned",
        "mandatory": false,
        "locked_reason": null,
        "bell_mutable": false,
        "delivery": "immediate",
        "channels": {
          "in_app": {
            "state": "always",
            "default": "on"
          },
          "email": {
            "state": "off",
            "default": "off"
          },
          "push": {
            "state": "on",
            "default": "on"
          },
          "whatsapp": {
            "state": "on",
            "default": "workspace"
          }
        }
      },
      {
        "key": "agenda_booked",
        "category": "agenda",
        "slug": "agenda_booked",
        "mandatory": false,
        "locked_reason": null,
        "bell_mutable": false,
        "delivery": "immediate",
        "channels": {
          "in_app": {
            "state": "always",
            "default": "on"
          },
          "email": {
            "state": "on",
            "default": "on"
          },
          "push": {
            "state": "on",
            "default": "on"
          },
          "whatsapp": {
            "state": "unavailable",
            "default": null
          }
        }
      },
      {
        "key": "payment_review_needed",
        "category": "payments",
        "slug": "payment_review_needed",
        "mandatory": true,
        "locked_reason": "customer_waiting",
        "bell_mutable": false,
        "delivery": "immediate",
        "channels": {
          "in_app": {
            "state": "locked",
            "default": "locked"
          },
          "email": {
            "state": "on",
            "default": "on"
          },
          "push": {
            "state": "on",
            "default": "on"
          },
          "whatsapp": {
            "state": "on",
            "default": "workspace"
          }
        }
      }
    ]
  }
}

Answers: 200 · 400 · 401 · 403 · 404 · 409 · 429

PUT /me/notification-preferences

Change notification preferences (preset and/or single cells)

JSON-merged: only the cells named change, everything else is kept. preset: important returns to the defaults (clears every per-type choice); all switches every switchable cell on; any changes entry without a preset makes the preset custom. 400 for an unknown type, a channel the type does not use, a mandatory (locked) cell, or the bell of a type that always appears in the bell. Returns the fresh catalog.

curl -X PUT https://api.vitrinadev.com/api/v1/me/notification-preferences \
  -H "Authorization: Bearer $VITRINA_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "changes": [
      {
        "key": "agenda_booked",
        "channel": "email",
        "enabled": false
      },
      {
        "key": "coach.finding_ready",
        "channel": "in_app",
        "enabled": false
      }
    ]
  }'

Example response (200)

{
  "data": {
    "preset": "important",
    "push_enabled": true,
    "categories": [
      "inbox",
      "agenda",
      "sales",
      "followups",
      "approvals",
      "payments",
      "agents",
      "integrations",
      "safety",
      "account"
    ],
    "types": [
      {
        "key": "assigned",
        "category": "inbox",
        "slug": "assigned",
        "mandatory": false,
        "locked_reason": null,
        "bell_mutable": false,
        "delivery": "immediate",
        "channels": {
          "in_app": {
            "state": "always",
            "default": "on"
          },
          "email": {
            "state": "off",
            "default": "off"
          },
          "push": {
            "state": "on",
            "default": "on"
          },
          "whatsapp": {
            "state": "on",
            "default": "workspace"
          }
        }
      },
      {
        "key": "agenda_booked",
        "category": "agenda",
        "slug": "agenda_booked",
        "mandatory": false,
        "locked_reason": null,
        "bell_mutable": false,
        "delivery": "immediate",
        "channels": {
          "in_app": {
            "state": "always",
            "default": "on"
          },
          "email": {
            "state": "on",
            "default": "on"
          },
          "push": {
            "state": "on",
            "default": "on"
          },
          "whatsapp": {
            "state": "unavailable",
            "default": null
          }
        }
      },
      {
        "key": "payment_review_needed",
        "category": "payments",
        "slug": "payment_review_needed",
        "mandatory": true,
        "locked_reason": "customer_waiting",
        "bell_mutable": false,
        "delivery": "immediate",
        "channels": {
          "in_app": {
            "state": "locked",
            "default": "locked"
          },
          "email": {
            "state": "on",
            "default": "on"
          },
          "push": {
            "state": "on",
            "default": "on"
          },
          "whatsapp": {
            "state": "on",
            "default": "workspace"
          }
        }
      }
    ]
  }
}

Answers: 200 · 400 · 401 · 403 · 404 · 409 · 429

GET /me/notifications

In-app notification feed for the active workspace (keyset-paginated)

The caller’s own bell, newest first. Only the last 14 days are returned (older rows expire and are deleted after 30 days); meta.unreadCount counts unread items inside that same window. Every row carries a typed target — where a click leads: record (one subject), list (a filtered list, e.g. the Búsquedas a daily summary counted) or page (a fixed screen) — never a URL. A live row is a standing condition (a broken channel, the approvals queue) refreshed in place and marked read when it ends. Requires a workspace member (a session or a personal token acting as one); an sk_* API key gets 403.

ParameterInTypeRequiredConstraints
cursorquerystringnomáx. 80
limitqueryintegerno≥ 1, ≤ 50
curl https://api.vitrinadev.com/api/v1/me/notifications \
  -H "Authorization: Bearer $VITRINA_KEY"

Example response (200)

{
  "data": [
    {
      "id": "019a3b1c-2d4e-7f00-8a1b-2c3d4e5f6a70",
      "type": "busqueda.daily_summary",
      "category": "followups",
      "actor_id": null,
      "entity_type": "tenant",
      "entity_id": "7b1f0c52-3e4a-4d8b-9c21-5a6b7c8d9e0f",
      "data": {
        "sent": 4,
        "failed": 1,
        "customers": [
          "Camila Rojas",
          "Diego Muñoz",
          "Paula Soto"
        ],
        "from": "2026-10-07T12:00:00.000Z",
        "to": "2026-10-08T12:00:00.000Z"
      },
      "target": {
        "kind": "list",
        "screen": "busquedas",
        "filter": {
          "notified_from": "2026-10-07T12:00:00.000Z",
          "notified_to": "2026-10-08T12:00:00.000Z",
          "status": "any"
        }
      },
      "secondary_target": {
        "kind": "list",
        "screen": "busquedas",
        "filter": {
          "notified_from": "2026-10-07T12:00:00.000Z",
          "notified_to": "2026-10-08T12:00:00.000Z",
          "notice": "failed",
          "status": "any"
        }
      },
      "live": false,
      "read_at": null,
      "created_at": "2026-10-08T12:00:04.512Z"
    },
    {
      "id": "019a3a77-90ab-7c00-9d1e-2f3a4b5c6d7e",
      "type": "agenda_booked",
      "category": "agenda",
      "actor_id": null,
      "entity_type": "appointment",
      "entity_id": "c4d5e6f7-0819-4a2b-8c3d-4e5f60718293",
      "data": {},
      "target": {
        "kind": "record",
        "record": "appointment",
        "id": "c4d5e6f7-0819-4a2b-8c3d-4e5f60718293"
      },
      "secondary_target": null,
      "live": false,
      "read_at": "2026-10-08T09:15:00.000Z",
      "created_at": "2026-10-07T21:40:11.003Z"
    }
  ],
  "meta": {
    "pagination": {
      "nextCursor": null
    },
    "unreadCount": 1
  }
}

Answers: 200 · 400 · 401 · 403 · 404 · 409 · 429

On this page