> ## Documentation Index
> Fetch the complete documentation index at: https://docs.bbrands.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Canales y segmentación

> Semántica de OneSignal por canal, categorías de notificación y cómo se segmenta a los usuarios por external_id y teléfono.

## Canales

| Canal           | Handler                          | Semántica de OneSignal                                                    |
| --------------- | -------------------------------- | ------------------------------------------------------------------------- |
| `push`          | `handleNotificationPush`         | `POST /notifications` con `contents`/`headings` + `target_channel: push`. |
| `in_app`        | `handleNotificationInApp`        | Push solo de datos (`content_available`, sin `contents`).                 |
| `sms`           | `handleNotificationSms`          | `POST /notifications` con `target_channel: sms` + teléfono E.164.         |
| `live_activity` | `handleNotificationLiveActivity` | Live Activity `start` / `update` según `data.action`.                     |

## Categorías y supresión

| Categoría       | ¿Opt-out?       |
| --------------- | --------------- |
| `marketing`     | Sí (suprimible) |
| `transactional` | No              |
| `payment`       | No              |
| `system`        | No              |

`NON_SUPPRESSIBLE_CATEGORIES = ["payment", "system", "transactional"]`. Los usuarios
nunca pueden silenciar estas categorías; el gating solo aplica a las suprimibles
(actualmente `marketing`).

## Segmentación

<CardGroup cols={2}>
  <Card title="Push / in-app / live activity" icon="id-badge">
    Segmentado por `include_aliases.external_id = [auth.users.id]`. El SDK móvil
    lo establece en el login.
  </Card>

  <Card title="SMS" icon="phone">
    Segmentado por `include_phone_numbers` con el teléfono E.164 resuelto desde
    `user_metadata.phone` / `user_phone`.
  </Card>
</CardGroup>

<Warning>
  `horizon-api` no tiene tokens de dispositivo. El SDK móvil debe llamar a
  `OneSignal.login(auth.users.id)` para que OneSignal pueda resolver el `external_id`
  al que apunta el backend.
</Warning>

## Clasificación de resultados

| Situación                                   | Resultado                               |
| ------------------------------------------- | --------------------------------------- |
| OneSignal 2xx con `id`                      | Procesado (`context.oneSignalId`).      |
| 200 con `errors` como "no subscribed users" | Skip registrado (entrega no-op).        |
| Teléfono ausente/inválido (SMS)             | `NonRetryableNotificationError` → skip. |
| Error 5xx / de red                          | Error → reintento con backoff → DLQ.    |
