Skip to main content

iOS SDK (Swift)

The official Zyphr SDK for iOS and macOS, built with URLSession and Swift async/await. Auto-generated from the OpenAPI specification.

Installation

Swift Package Manager

Add the following to your Package.swift:

dependencies: [
.package(url: "https://github.com/arcraz/zyphr.git", from: "0.1.0")
]

Or in Xcode: File > Add Package Dependencies and enter the repository URL.

CocoaPods

pod 'ZyphrSDK', '~> 0.1.0'

Configuration

import ZyphrSDK

let config = Configuration(
apiKey: "zy_live_xxx",
basePath: "https://api.zyphr.dev/v1" // Optional custom endpoint
)
Security

Never hardcode API keys in your app. Store them securely using environment variables during development and a secure backend proxy in production. Mobile apps should use a backend endpoint that proxies Zyphr API calls to avoid exposing your API key.

API Classes

The SDK exposes one API class per resource:

ClassDescription
EmailsAPISend and manage email messages
PushAPISend push notifications
SmsAPISend SMS text messages
InboxAPIIn-app notification inbox
SubscribersAPIManage subscriber profiles
DevicesAPIRegister push notification devices
TemplatesAPICreate and manage templates
TopicsAPIPub/sub topics
WebhooksAPIConfigure webhook endpoints

Emails

Send Email

let emails = EmailsAPI(configuration: config)

let result = try await emails.sendEmail(
sendEmailRequest: SendEmailRequest(
to: "user@example.com",
from: "hello@yourapp.com",
subject: "Welcome!",
html: "<h1>Hello!</h1><p>Thanks for signing up.</p>",
text: "Hello! Thanks for signing up.",
replyTo: "support@yourapp.com",
tags: ["welcome", "onboarding"],
metadata: ["userId": "user_123"]
)
)
print("Email sent: \(result.id)")

Send with Template

let result = try await emails.sendEmail(
sendEmailRequest: SendEmailRequest(
to: "user@example.com",
templateId: "welcome-email",
templateData: [
"name": "John",
"actionUrl": "https://yourapp.com/activate",
]
)
)

Get Email Status

let email = try await emails.getEmail(id: "msg_abc123")
print("Status: \(email.status)")

List Emails

let response = try await emails.listEmails(page: 1, perPage: 25)
for email in response.data {
print("\(email.id): \(email.status)")
}

Push Notifications

Send Push

let push = PushAPI(configuration: config)

try await push.sendPush(
sendPushRequest: SendPushRequest(
userId: "user_123",
title: "New Message",
body: "You have a new message",
data: ["messageId": "msg_456"]
)
)

Send to Specific Device

try await push.sendPush(
sendPushRequest: SendPushRequest(
deviceId: "device_abc",
title: "New Message",
body: "You have a new message"
)
)

Silent Push

try await push.sendPush(
sendPushRequest: SendPushRequest(
userId: "user_123",
contentAvailable: true,
data: ["type": "sync", "resource": "messages"]
)
)

Rich Notifications

try await push.sendPush(
sendPushRequest: SendPushRequest(
userId: "user_123",
title: "Photo shared",
body: "Jane shared a photo with you",
imageUrl: "https://yourapp.com/photo.jpg",
badge: 3,
sound: "default",
actionButtons: [
ActionButton(id: "view", title: "View"),
ActionButton(id: "dismiss", title: "Dismiss"),
]
)
)

SMS

let sms = SmsAPI(configuration: config)

let result = try await sms.sendSms(
sendSmsRequest: SendSmsRequest(
to: "+14155551234",
body: "Your verification code is 123456"
)
)
print("SMS sent: \(result.id)")

In-App Inbox

let inbox = InboxAPI(configuration: config)

try await inbox.sendInboxNotification(
sendInboxRequest: SendInboxRequest(
subscriberId: "user_123",
title: "New Comment",
body: "John commented on your post",
actionUrl: "/posts/123#comments"
)
)

Subscribers

Create Subscriber

let subscribers = SubscribersAPI(configuration: config)

let subscriber = try await subscribers.createSubscriber(
createSubscriberRequest: CreateSubscriberRequest(
externalId: "user_123",
email: "user@example.com",
phone: "+14155551234",
name: "John Doe",
metadata: ["plan": "pro"]
)
)

Get Subscriber

let subscriber = try await subscribers.getSubscriber(id: "user_123")
print("Name: \(subscriber.name ?? "unknown")")

Update Subscriber

try await subscribers.updateSubscriber(
id: "user_123",
updateSubscriberRequest: UpdateSubscriberRequest(
name: "Jane Doe",
metadata: ["plan": "enterprise"]
)
)

Delete Subscriber

try await subscribers.deleteSubscriber(id: "user_123")

Device Management

Register Device

let devices = DevicesAPI(configuration: config)

try await devices.registerDevice(
registerDeviceRequest: RegisterDeviceRequest(
subscriberId: "user_123",
token: apnsToken,
platform: .ios,
appVersion: Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String,
osVersion: UIDevice.current.systemVersion
)
)

List Devices

let response = try await devices.listDevices(userId: "user_123")
for device in response.data {
print("\(device.platform): \(device.lastSeenAt)")
}

Unregister Device

try await devices.deleteDevice(id: "device_abc")

Topics

Subscribe to Topic

let topics = TopicsAPI(configuration: config)

try await topics.subscribe(
topicId: "promotions",
subscriberId: "user_123"
)

Unsubscribe from Topic

try await topics.unsubscribe(
topicId: "promotions",
subscriberId: "user_123"
)

Send to Topic

try await push.sendToTopic(
topicId: "promotions",
sendPushRequest: SendPushRequest(
title: "Flash Sale!",
body: "50% off everything today"
)
)

Error Handling

All API methods are async and throw errors on failure:

do {
try await emails.sendEmail(request)
} catch let error as ErrorResponse {
switch error {
case .error(let statusCode, let data, _, _):
let message = String(data: data ?? Data(), encoding: .utf8) ?? "Unknown error"
print("API Error (\(statusCode)): \(message)")

switch statusCode {
case 400: print("Bad request — check your parameters")
case 401: print("Unauthorized — check your API key")
case 404: print("Resource not found")
case 429: print("Rate limited — slow down")
default: print("Server error")
}
}
} catch {
print("Network error: \(error.localizedDescription)")
}

Retry with Exponential Backoff

func withRetry<T>(maxAttempts: Int = 3, operation: () async throws -> T) async throws -> T {
var lastError: Error?

for attempt in 0..<maxAttempts {
do {
return try await operation()
} catch let error as ErrorResponse {
if case .error(let statusCode, _, _, _) = error, statusCode == 429 || statusCode >= 500 {
lastError = error
let delay = pow(2.0, Double(attempt))
try await Task.sleep(nanoseconds: UInt64(delay * 1_000_000_000))
continue
}
throw error // Don't retry 4xx errors (except 429)
}
}

throw lastError!
}

// Usage
let result = try await withRetry {
try await emails.sendEmail(request)
}

Thread Safety

All API classes are safe to use from any actor or thread. Each API call creates an independent URLSession task.

For SwiftUI, you can call SDK methods directly from Task blocks:

struct SendButton: View {
var body: some View {
Button("Send") {
Task {
try await emails.sendEmail(request)
}
}
}
}

Requirements

  • iOS 15.0+ / macOS 12.0+
  • Swift 5.5+
  • Xcode 14.0+

Next Steps