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

# Swift push

> APNs-direct push with zero Firebase: forward the token from your AppDelegate and you're done.

On native iOS, ClarioDesk delivers push straight through APNs. There is no
Firebase SDK to add, no google-services plist, no third-party messaging
dependency — the wiring is one line in your AppDelegate.

## Wire the token

Request notification permission and register for remote notifications as you
normally would, then forward the raw APNs token:

```swift theme={null}
import ClarioDesk

func application(
  _ app: UIApplication,
  didRegisterForRemoteNotificationsWithDeviceToken token: Data
) {
  ClarioDesk.setAPNSDeviceToken(token)
}
```

That's the whole client side. The SDK registers the token with the backend and
re-registers when iOS rotates it.

## Upload your APNs key once

In the [dashboard](https://dashboard.clariodesk.com), open your app's push settings
and upload the APNs auth key (the `.p8` file from your Apple Developer
account, with its key id and team id). Delivery then goes ClarioDesk → APNs →
device, from your own Apple credentials.

## Deep-link on tap

Route ClarioDesk notifications in your tap handler, then open the thread:

```swift theme={null}
func userNotificationCenter(
  _ center: UNUserNotificationCenter,
  didReceive response: UNNotificationResponse,
  withCompletionHandler completionHandler: @escaping () -> Void
) {
  let userInfo = response.notification.request.content.userInfo
  if let payload = ClarioDesk.openTicketFromPush(userInfo) {
    // Prebuilt UI: present straight into the thread.
    ClarioDeskWidgets.openConversation(payload.ticketId)
  }
  completionHandler()
}
```

`openTicketFromPush` parses the payload, returns it (or `nil` if the
notification isn't ours), and emits the ticket id on `ClarioDesk.pushOpened` —
if the support modal is already presented, it navigates itself. Headless hosts
route with the returned payload or subscribe:

```swift theme={null}
ClarioDesk.subscribePushOpened { ticketId in
  navigateToSupport(ticketId)
}
```

In a shared handler, distinguish ours without consuming:

```swift theme={null}
if ClarioDesk.isClarioMessage(userInfo) { /* ours */ }
let payload = ClarioDesk.parsePushPayload(userInfo) // nil if not ours
```

## Preferences

```swift theme={null}
let prefs = try await ClarioDesk.getNotificationPreferences()
_ = try await ClarioDesk.setNotificationPreferences(
  pushEnabled: true,
  quietHoursStart: "22:00",
  quietHoursEnd: "08:00",
  timezone: "America/New_York"
)
```

## Already shipping Firebase?

A host that already runs Firebase Messaging can hand the SDK FCM tokens
instead: implement the `PushTokenProvider` protocol against
`Messaging.messaging()` and pass it in `ClarioDeskOptions`, or call
`ClarioDesk.registerPushToken(token)` from your own messaging callback. The
SDK itself never imports Firebase either way.

<Note>
  The backend is presence-aware: when the user is actively connected over
  realtime, the push is suppressed — they're already seeing the reply live. See
  the [push concept page](/concepts/push-notifications).
</Note>
