Docs

Swift: Push, attestation and crashes

Register devices for push, prove requests come from your real app, and report crashes with the Swift SDK.

Updated Oct 24, 2026

Register devices for push, prove requests come from your real app, and report crashes. Every call runs as the client's signed-in user, so your project's policies and row-level security apply. Types and members are listed in source order; each one links to its HTTP endpoint where it maps to one.

#Types and members

SovariaPush

Push notifications for the signed-in app user. Register the token after sign-in: Sending happens on your server or in a function with the service role key (api.push.send), never from the app.

public final class SovariaPush: @unchecked Sendable

SovariaPush.register

Register (or move to this user) a push token.

public func register(token: String, platform: String, provider: String? = nil, appId: String? = nil,
                     topics: [String]? = nil, locale: String? = nil) async throws -> PushDevice

provider is fcm or apns; the token is tied to the client's device.

SovariaPush.registerAPNs

The APNs device token from didRegisterForRemoteNotificationsWithDeviceToken (sent as hex, provider apns).

public func registerAPNs(deviceToken: Data, platform: String = "", appId: String? = nil, topics: [String]? = nil,
                         locale: String? = nil) async throws -> PushDevice

SovariaPush.unregister

Drop a token (sign-out, notifications turned off).

public func unregister(_ token: String) async throws

Safe to call twice.

SovariaPush.devices

public func devices() async throws -> [PushDevice]

SovariaPush.subscribe

public func subscribe(_ deviceRowId: String, topics: [String]) async throws -> PushDevice

SovariaPush.unsubscribe

public func unsubscribe(_ deviceRowId: String, topics: [String]) async throws -> PushDevice

PushDevice

public struct PushDevice: @unchecked Sendable

PushDevice.id

A property.

public let id: String

PushDevice.platform

A property.

public let platform: String

PushDevice.provider

A property.

public let provider: String

PushDevice.topics

A property.

public let topics: [String]

PushDevice.raw

A property.

public let raw: [String: Any]

AttestationProvider

Produces platform evidence for an attestation challenge — the fields of POST /api/v1/attest/exchange. Use AppAttestProvider on iOS devices, DebugAttestationProvider on simulators and CI, or your own.

public protocol AttestationProvider: Sendable

AttestationProvider.evidence

func evidence(challenge: String) async throws -> [String: Any]

DebugAttestationProvider

Stands in for a device on simulators and CI. Create the token in the console (Mobile › App attestation › Debug tokens); never ship it in a release build.

public struct DebugAttestationProvider: AttestationProvider

DebugAttestationProvider.debugToken

A property.

public let debugToken: String

DebugAttestationProvider.DebugAttestationProvider.init

Create an instance.

public init(debugToken: String)

DebugAttestationProvider.evidence

public func evidence(challenge: String) async throws -> [String: Any]

AttestationManager

Keeps a valid attestation token and refreshes it before it expires. The client sends it as X-Sovaria-Attestation and fetches a new one after a 401 APP_ATTESTATION_REQUIRED (same as the Dart client).

public final class AttestationManager: @unchecked Sendable

AttestationManager.provider

A property.

public let provider: AttestationProvider

AttestationManager.margin

A property.

public let margin: TimeInterval

AttestationManager.token

The current token, fetching one first when there is none or it is about to expire.

public func token() async -> String?

Nil when attestation fails, so requests still go out (the project may only be monitoring).

AttestationManager.refresh

Fetch a new token now; concurrent callers share one request.

public func refresh() async throws -> String?

AttestationManager.clear

public func clear()

AppAttestProvider

App Attest on devices that support it (iOS 14+), DeviceCheck otherwise. The key id is kept in storage; the first exchange attests the key (attestation), later ones send an assertion over SHA-256(challenge). appId is the bundle identifier registered in the console; set development for debug builds (App Attest's development environment). App Attest doesn't run on the simulator — use DebugAttestationProvider there.

public final class AppAttestProvider: AttestationProvider, @unchecked Sendable

AppAttestProvider.appId

A property.

public let appId: String

AppAttestProvider.development

A property.

public let development: Bool

AppAttestProvider.AppAttestProvider.init

Create an instance.

public init(appId: String, storage: SessionStorage, development: Bool = false, keyName: String = "")

AppAttestProvider.evidence

public func evidence(challenge: String) async throws -> [String: Any]

Breadcrumb

A step that led up to a crash (a Sovaria request the SDK made, or one you added).

public struct Breadcrumb: Sendable

Breadcrumb.category

A property.

public let category: String

Breadcrumb.message

A property.

public let message: String

Breadcrumb.timestamp

A property.

public let timestamp: String

Breadcrumb.Breadcrumb.init

Create an instance.

public init(category: String, message: String, timestamp: String = ISO8601DateFormatter().string(from: Date()))

SovariaCrashes

App crash reporting. Uncaught NSExceptions and anything you pass to capture(_:) are grouped into issues in the console (Monitor › Crashes). Each report carries the error type, message, stack, the release, the platform and device, the last 50 breadcrumbs and the signed-in user (the server takes the user from the request token). A fatal crash can't be sent while the process is dying, so it is written to the offline store and sent on the next launch (call install early, with a durable store). Handled capture(_:) reports send in the background. v1 covers managed crashes (NSException) and capture(_:). Raw POSIX-signal crashes (SIGSEGV/SIGABRT) need a dedicated signal-safe reporter and are a planned addition; capture those paths with capture(_:) where you can.

public final class SovariaCrashes: @unchecked Sendable

SovariaCrashes.install

Start capturing.

public func install(release: String? = nil, environment: String? = nil, store: OfflineStore? = nil)

Pass a durable store (or enable offline first) so a fatal crash survives to the next launch.

SovariaCrashes.uninstall

public func uninstall()

SovariaCrashes.addBreadcrumb

Add a breadcrumb (a step that led up to a crash).

public func addBreadcrumb(category: String, message: String)

SovariaCrashes.capture

Report a handled error.

public func capture(_ error: Error, handled: Bool = true, tags: [String: String] = [:],
                    extra: [String: Any] = [:], fingerprint: String? = nil) -> Bool

Returns false if crash reporting isn't installed.

SovariaCrashes.flush

Send queued reports now.

public func flush() async