# Gotify Transport Adaptor

Source: https://supernotify.rhizomatics.org.uk/latest/transports/gotify/

## Discovery

**Default delivery.** SuperNotify looks for a registered `notify.*` service backed by the `custom_components.gotify.notify` HACS platform module. If found and no `gotify` delivery is defined, a `gotify` delivery is generated automatically using that service and fires on every notification. Manually configuring your own `gotify` delivery with an explicit `action:` (see [Notes](#notes) below) still works and takes precedence.

## Motivation

Access Gotify's richer features: click-through URLs, `bigImageUrl` (expanded image on notification tap), Markdown rendering, and Android intent actions on receive. Requires the [homeassistant-gotify](https://github.com/1RandomDev/homeassistant-gotify) HACS integration

## Notes

- **`action:` is required** — unlike most transports, there is no default action. The HACS integration lets users name the service freely (`notify.gotify`, `notify.my_server`, etc.), so `validate_action()` accepts any `notify.*` service and warns if the action is missing or uses the wrong domain.
- **Camera snapshot** — `gotify_attach_image: true` triggers a `camera.snapshot` call and builds a publicly-reachable URL. `gotify_image_url` (explicit URL) takes precedence and skips the snapshot entirely.
- **No raw_data passthrough** — the HACS payload schema is fixed (`{message, title, data: {priority, extras}}`). Unknown keys would cause silent failures or future breakage; they are intentionally dropped (documented with an inline comment).
- **Separate snapshot path** — uses `supernotify_gotify_snapshot.jpg` (not the ntfy snapshot path) to prevent race conditions when both transports fire concurrently.

______________________________________________________________________

## Testing

Tested on Home Assistant 2026.3.4 with:

- Gotify server v2.4.0 (self-hosted, local network)
- HACS integration `1RandomDev/homeassistant-gotify` v1.0.2
- SuperNotify v1.12.2

**Test cases verified on real HA:**

```yaml
# 1. Basic message — priority auto-mapping
action: supernotify.notify
data:
  message: "Test base Gotify"
  title: "SuperNotify Test"
  delivery: [gotify_base]
# Result: notification received, priority=5 (int) in Gotify ✅

# 2. Critical alert — priority mapping
action: supernotify.notify
data:
  message: "Allarme ingresso attivo"
  title: "🚨 Allarme"
  delivery: [gotify_base]
  priority: critical
# Result: priority=10, notification shown with max urgency ✅

# 3. With bigImageUrl from camera snapshot
action: supernotify.notify
data:
  message: "Movimento rilevato"
  delivery: [gotify_con_camera]
  extra_data:
    gotify_attach_image: true
  media:
    camera_entity_id: camera.ingresso
# Result: snapshot taken, bigImageUrl present, image visible on tap ✅

# 4. With click URL and Markdown
action: supernotify.notify
data:
  message: "**Porta aperta** — controlla la dashboard"
  delivery: [gotify_base]
  extra_data:
    gotify_click: "https://ha.local:8123/lovelace/sicurezza"
    gotify_markdown: true
# Result: bold text rendered, tap opens HA dashboard ✅

# 5. Missing action: — validate_action warning
# Delivery configured without action: notify.*
# Result: warning logged, delivery suppressed, no crash ✅
```

**Unit tests:** `tests/components/supernotify/test_transport_gotify.py`

- 35 test cases covering: `_build_extras()` (all combinations), `validate_action()`, `deliver()` happy path, all 5 priority levels, `gotify_priority` override (int/string/clamp/invalid), `boolify()` behaviour for YAML strings, `gotify_image_url` precedence over `attach_image`, camera snapshot success/failure, no `gotify_*` key leakage into payload, service exception handling, `supported_features`, `default_config`.

______________________________________________________________________

## Priority mapping reference

| SuperNotify | Gotify int | Gotify label |
| ----------- | ---------- | ------------ |
| `critical`  | 10         | max urgency  |
| `high`      | 7          | high         |
| `medium`    | 5          | default      |
| `low`       | 2          | low          |
| `minimum`   | 0          | silent/min   |

______________________________________________________________________

## Configuration example

```yaml
# configuration.yaml (HA)
notify:
  - platform: gotify
    name: gotify
    url: http://gotify.local
    token: !secret gotify_token

# supernotify delivery config
deliveries:
  gotify_allarme:
    transport: gotify
    action: notify.gotify          # only needed if auto-discovery doesn't find your service
    priority: high
    data:
      gotify_click: "https://ha.local:8123/lovelace/sicurezza"
      gotify_attach_image: true
      gotify_markdown: true

  gotify_info:
    transport: gotify
    action: notify.gotify
    priority: low                  # → Gotify priority 2
```

______________________________________________________________________

## Deviations from standard patterns (intentional)

**No `raw_data` passthrough** (CLAUDE.md §4 pattern): The standard pattern passes residual `raw_data` keys to `action_data`. For Gotify this is deliberately omitted — the HACS service has a fixed schema and unknown top-level keys cause silent failures or HTTP 400s on future integration updates. This decision is documented with an inline comment in `deliver()`.

**No static default `action:`**: `default_config` sets no fixed `action`, since the HACS service name is user-controlled. `auto_configure()` fills it in dynamically once discovered (see [Discovery](#discovery)); `validate_action()` still provides a clear warning when a manually configured delivery omits `action:`.

______________________________________________________________________

## Related

- Fixes the `generic` transport workaround for Gotify (priority string bug)
- Follows the same transport pattern as the ntfy transport (PR #TBD)
- HACS integration: https://github.com/1RandomDev/homeassistant-gotify
- Gotify extras docs: https://gotify.net/docs/msgextras
