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
)
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:
| Class | Description |
|---|---|
EmailsAPI | Send and manage email messages |
PushAPI | Send push notifications |
SmsAPI | Send SMS text messages |
InboxAPI | In-app notification inbox |
SubscribersAPI | Manage subscriber profiles |
DevicesAPI | Register push notification devices |
TemplatesAPI | Create and manage templates |
TopicsAPI | Pub/sub topics |
WebhooksAPI | Configure 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
- Push Notifications for iOS — Complete native iOS push integration guide
- Push Notifications API — Full push API reference
- Device Management — Managing registered devices