Skip to main content

Android SDK (Kotlin)

The official Zyphr SDK for Android and JVM, built with OkHttp4 and Kotlin coroutines. Auto-generated from the OpenAPI specification.

Installation

Gradle (Kotlin DSL)

dependencies {
implementation("dev.zyphr:zyphr-sdk:0.1.0")
}

Gradle (Groovy)

implementation 'dev.zyphr:zyphr-sdk:0.1.0'

Configuration

import dev.zyphr.sdk.infrastructure.ApiClient

val client = ApiClient(
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 BuildConfig fields 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

All API methods are suspend functions and must be called from a coroutine scope.

Emails

Send Email

import dev.zyphr.sdk.api.EmailsApi
import dev.zyphr.sdk.models.SendEmailRequest

val emails = EmailsApi(client)

val result = emails.sendEmail(
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 = listOf("welcome", "onboarding"),
metadata = mapOf("userId" to "user_123")
)
)
println("Email sent: ${result.id}")

Send with Template

val result = emails.sendEmail(
SendEmailRequest(
to = "user@example.com",
templateId = "welcome-email",
templateData = mapOf(
"name" to "John",
"actionUrl" to "https://yourapp.com/activate"
)
)
)

Get Email Status

val email = emails.getEmail(id = "msg_abc123")
println("Status: ${email.status}")

List Emails

val response = emails.listEmails(page = 1, perPage = 25)
for (email in response.data) {
println("${email.id}: ${email.status}")
}

Push Notifications

Send Push

import dev.zyphr.sdk.api.PushApi
import dev.zyphr.sdk.models.SendPushRequest

val push = PushApi(client)

push.sendPush(
SendPushRequest(
userId = "user_123",
title = "New Message",
body = "You have a new message",
data = mapOf("messageId" to "msg_456")
)
)

Send to Specific Device

push.sendPush(
SendPushRequest(
deviceId = "device_abc",
title = "New Message",
body = "You have a new message"
)
)

Silent Push

push.sendPush(
SendPushRequest(
userId = "user_123",
contentAvailable = true,
data = mapOf("type" to "sync", "resource" to "messages")
)
)

Rich Notifications

push.sendPush(
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 = listOf(
ActionButton(id = "view", title = "View"),
ActionButton(id = "dismiss", title = "Dismiss")
)
)
)

SMS

import dev.zyphr.sdk.api.SmsApi
import dev.zyphr.sdk.models.SendSmsRequest

val sms = SmsApi(client)

val result = sms.sendSms(
SendSmsRequest(
to = "+14155551234",
body = "Your verification code is 123456"
)
)
println("SMS sent: ${result.id}")

In-App Inbox

import dev.zyphr.sdk.api.InboxApi
import dev.zyphr.sdk.models.SendInboxRequest

val inbox = InboxApi(client)

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

Subscribers

Create Subscriber

import dev.zyphr.sdk.api.SubscribersApi
import dev.zyphr.sdk.models.CreateSubscriberRequest

val subscribers = SubscribersApi(client)

val subscriber = subscribers.createSubscriber(
CreateSubscriberRequest(
externalId = "user_123",
email = "user@example.com",
phone = "+14155551234",
name = "John Doe",
metadata = mapOf("plan" to "pro")
)
)

Get Subscriber

val subscriber = subscribers.getSubscriber(id = "user_123")
println("Name: ${subscriber.name}")

Update Subscriber

subscribers.updateSubscriber(
id = "user_123",
UpdateSubscriberRequest(
name = "Jane Doe",
metadata = mapOf("plan" to "enterprise")
)
)

Delete Subscriber

subscribers.deleteSubscriber(id = "user_123")

Device Management

Register Device

import dev.zyphr.sdk.api.DevicesApi
import dev.zyphr.sdk.models.RegisterDeviceRequest

val devices = DevicesApi(client)

devices.registerDevice(
RegisterDeviceRequest(
subscriberId = "user_123",
token = fcmToken,
platform = RegisterDeviceRequest.Platform.android,
appVersion = BuildConfig.VERSION_NAME,
osVersion = Build.VERSION.RELEASE
)
)

List Devices

val response = devices.listDevices(userId = "user_123")
for (device in response.data) {
println("${device.platform}: ${device.lastSeenAt}")
}

Unregister Device

devices.deleteDevice(id = "device_abc")

Topics

Subscribe to Topic

import dev.zyphr.sdk.api.TopicsApi

val topics = TopicsApi(client)

topics.subscribe(
topicId = "promotions",
subscriberId = "user_123"
)

Unsubscribe from Topic

topics.unsubscribe(
topicId = "promotions",
subscriberId = "user_123"
)

Send to Topic

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

Error Handling

All API methods are suspend functions that throw exceptions on failure:

import dev.zyphr.sdk.infrastructure.ClientException
import dev.zyphr.sdk.infrastructure.ServerException

try {
emails.sendEmail(request)
} catch (e: ClientException) {
// 4xx errors
println("Client error (${e.statusCode}): ${e.message}")
when (e.statusCode) {
400 -> println("Bad request — check your parameters")
401 -> println("Unauthorized — check your API key")
404 -> println("Resource not found")
429 -> println("Rate limited — slow down")
}
} catch (e: ServerException) {
// 5xx errors
println("Server error (${e.statusCode}): ${e.message}")
} catch (e: Exception) {
// Network errors
println("Network error: ${e.message}")
}

Retry with Exponential Backoff

suspend fun <T> withRetry(maxAttempts: Int = 3, operation: suspend () -> T): T {
var lastException: Exception? = null

repeat(maxAttempts) { attempt ->
try {
return operation()
} catch (e: ClientException) {
if (e.statusCode == 429) {
lastException = e
delay(2.0.pow(attempt).toLong() * 1000)
} else {
throw e // Don't retry other 4xx errors
}
} catch (e: ServerException) {
lastException = e
delay(2.0.pow(attempt).toLong() * 1000)
}
}

throw lastException!!
}

// Usage
val result = withRetry {
emails.sendEmail(request)
}

Coroutines & ViewModel Integration

All API methods are suspend functions. Use them with Android's coroutine scopes:

ViewModel

class NotificationViewModel(private val push: PushApi) : ViewModel() {

private val _sendState = MutableStateFlow<Result<Unit>?>(null)
val sendState: StateFlow<Result<Unit>?> = _sendState

fun sendNotification(userId: String, title: String, body: String) {
viewModelScope.launch {
_sendState.value = runCatching {
push.sendPush(
SendPushRequest(
userId = userId,
title = title,
body = body
)
)
}
}
}
}

Jetpack Compose

@Composable
fun SendNotificationScreen(viewModel: NotificationViewModel) {
val sendState by viewModel.sendState.collectAsState()

Button(onClick = {
viewModel.sendNotification("user_123", "Hello", "World")
}) {
Text("Send Notification")
}

sendState?.let { result ->
result.onSuccess { Text("Sent!") }
result.onFailure { Text("Error: ${it.message}") }
}
}

Thread Safety

The SDK uses OkHttp's connection pool and is safe to share across threads and coroutine scopes. Create a single ApiClient instance and reuse it throughout your app:

// In your Application class or DI module
val zyphrClient = ApiClient(apiKey = BuildConfig.ZYPHR_API_KEY)

// Inject into ViewModels/repositories
val emailsApi = EmailsApi(zyphrClient)
val pushApi = PushApi(zyphrClient)

Requirements

  • Android API 21+ (Android 5.0)
  • Kotlin 1.8+
  • OkHttp 4.x

Next Steps