SDK Documentation
Cuti-E provides native SDKs for iOS and Android that let you collect user feedback directly in your mobile app. The SDKs handle creating conversations, sending messages, and receiving push notifications - all with minimal code.
Getting Started: You need two things from the Admin Dashboard:
1. API Key - Found in Settings → API Keys
2. App ID - Create your app in Settings → Apps
Quick Start
Choose your platform to get started in under 5 minutes:
1. Add the Package
In Xcode, go to File → Add Package Dependencies and enter:
https://github.com/cuti-e/ios-sdk
2. Configure the SDK
import CutiE
// In AppDelegate or @main App
CutiE.shared.configure(
apiKey: "your_api_key_here",
appId: "your_app_id_here" // Create in Settings → Apps
)
3. Show Feedback Form
import SwiftUI
import CutiE
struct ContentView: View {
@State private var showFeedback = false
var body: some View {
Button("Send Feedback") {
showFeedback = true
}
.sheet(isPresented: $showFeedback) {
CutiEFeedbackView { conversationId in
print("Submitted: \(conversationId)")
}
}
}
}
1. Add the Dependency
In your settings.gradle.kts, add JitPack:
dependencyResolutionManagement {
repositories {
maven { url = uri("https://jitpack.io") }
}
}
Then add the dependency in build.gradle.kts:
dependencies {
implementation("com.github.Stig-Johnny.cutie:cutie:1.0.0")
}
2. Configure the SDK
import com.cutie.sdk.CutiE
// In your Application class
class MyApplication : Application() {
override fun onCreate() {
super.onCreate()
CutiE.getInstance(this).configure(
apiKey = "your_api_key_here",
appId = "com.yourcompany.yourapp"
)
}
}
3. Show Feedback Form
import com.cutie.sdk.CutiEFeedbackView
@Composable
fun MyScreen() {
var showFeedback by remember { mutableStateOf(false) }
Button(onClick = { showFeedback = true }) {
Text("Send Feedback")
}
if (showFeedback) {
CutiEFeedbackView(
onDismiss = { showFeedback = false },
onSuccess = { conversationId ->
println("Submitted: $conversationId")
}
)
}
}
Configuration Options
| Option | Type | Description |
|---|---|---|
apiKey |
String | Your API key from the admin dashboard (required) |
appId |
String | Your app's unique identifier, e.g., bundle ID (required) |
apiURL |
String | API endpoint (default: production server) |
Testing: Use the sandbox environment for development:
apiURL: "https://cutie-worker-sandbox.invotekas.workers.dev"
iOS Installation
Swift Package Manager
Add Cuti-E to your project using Xcode:
- File → Add Package Dependencies...
- Enter:
https://github.com/cuti-e/ios-sdk - Choose version or branch
- Add to your target
Manual Installation
Add to your Package.swift:
dependencies: [
.package(url: "https://github.com/cuti-e/ios-sdk.git", from: "1.0.88")
],
targets: [
.target(
name: "YourTarget",
dependencies: ["CutiE"]
)
]
Requirements
- iOS 15.0+ / macOS 12.0+
- Swift 5.9+
- Xcode 15.0+
iOS Basic Usage
Create a Conversation (Callback)
CutiE.shared.createConversation(
category: .bug,
message: "The app crashes when I tap save",
title: "Crash on Save"
) { result in
switch result {
case .success(let conversationId):
print("Created: \(conversationId)")
case .failure(let error):
print("Error: \(error.localizedDescription)")
}
}
List Conversations (iOS 15+)
// Using async/await
let conversations = try await CutiE.shared.getConversations()
for conv in conversations {
print("\(conv.title ?? "Untitled") - \(conv.status)")
}
Send a Message (iOS 15+)
// Using async/await
let message = try await CutiE.shared.sendMessage(
conversationId: "conv_abc123",
message: "Thanks for the help!"
)
iOS Feedback View
The SDK includes a ready-to-use SwiftUI feedback form:
import SwiftUI
import CutiE
struct SettingsView: View {
@State private var showFeedback = false
var body: some View {
List {
Button("Send Feedback") {
showFeedback = true
}
}
.sheet(isPresented: $showFeedback) {
CutiEFeedbackView { conversationId in
// Called when feedback is submitted
print("Created conversation: \(conversationId)")
}
}
}
}
iOS In-app Inbox
Let users view their feedback conversations and admin replies directly in your app (iOS 15+).
UX Best Practice: Add an inbox icon to your navigation bar so users can easily access their feedback from anywhere in your app. Don't bury it deep in Settings!
Recommended: Navigation Bar Icon with Badge
Add a persistent inbox icon with an unread message badge in your main view's navigation bar:
import SwiftUI
import CutiE
struct MainView: View {
@State private var showInbox = false
@State private var showFeedback = false
@State private var unreadCount = 0
var body: some View {
NavigationView {
YourContentView()
.navigationTitle("Home")
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
HStack(spacing: 16) {
// Inbox button with badge
Button { showInbox = true } label: {
ZStack(alignment: .topTrailing) {
Image(systemName: "tray.full")
if unreadCount > 0 {
Text(unreadCount > 99 ? "99+" : "\(unreadCount)")
.font(.system(size: 10, weight: .bold))
.foregroundColor(.white)
.padding(.horizontal, 5)
.padding(.vertical, 2)
.background(Color.red)
.clipShape(Capsule())
.offset(x: 8, y: -8)
}
}
}
// Submit feedback button
Button { showFeedback = true } label: {
Image(systemName: "exclamationmark.bubble")
}
}
}
}
.sheet(isPresented: $showInbox) {
CutiEInboxView()
}
.sheet(isPresented: $showFeedback) {
CutiEFeedbackView { _ in }
}
.task {
await loadUnreadCount()
}
}
}
private func loadUnreadCount() async {
guard CutiE.shared.isConfigured else { return }
do {
unreadCount = try await CutiE.shared.getUnreadCount()
} catch {
print("Failed to load unread count: \(error)")
}
}
}
Alternative: Settings Menu
struct SettingsView: View {
@State private var showInbox = false
var body: some View {
List {
Button("My Feedback") {
showInbox = true
}
}
.sheet(isPresented: $showInbox) {
CutiEInboxView()
}
}
}
UIKit Integration
// Present inbox modally from any view controller
CutiE.shared.showInbox()
// Or from a specific view controller
CutiE.shared.showInbox(from: viewController)
Async/Await API
// Get all conversations
let conversations = try await CutiE.shared.getConversations()
// Get single conversation with messages
let conversation = try await CutiE.shared.getConversation(id: "conv_abc123")
// Send a reply
let message = try await CutiE.shared.sendMessage(
conversationId: "conv_abc123",
message: "Thanks for the help!"
)
// Get unread message count (for badge display)
let unreadCount = try await CutiE.shared.getUnreadCount()
Android Installation
Gradle (via JitPack)
Add JitPack to your root settings.gradle.kts:
dependencyResolutionManagement {
repositories {
google()
mavenCentral()
maven { url = uri("https://jitpack.io") }
}
}
Add the dependency to your app's build.gradle.kts:
dependencies {
implementation("com.github.Stig-Johnny.cutie:cutie:1.0.0")
}
Requirements
- Android 7.0 (API 24) or higher
- Kotlin 1.9+
- Gradle 8.0+
Android Basic Usage
Create a Conversation
CutiE.getInstance(context).createConversation(
category = ConversationCategory.BUG,
message = "The app crashes when I tap save",
title = "Crash on Save"
) { result ->
result.onSuccess { conversation ->
println("Created: ${conversation.id}")
}.onFailure { error ->
println("Error: ${error.message}")
}
}
List Conversations
CutiE.getInstance(context).listConversations { result ->
result.onSuccess { conversations ->
conversations.forEach { conv ->
println("${conv.title} - ${conv.status}")
}
}
}
Send a Message
CutiE.getInstance(context).sendMessage(
message = "Thanks for the help!",
conversationID = "conv_abc123"
) { result ->
// Handle result
}
Android Feedback View
The SDK includes a Jetpack Compose feedback form:
import com.cutie.sdk.CutiEFeedbackView
@Composable
fun SettingsScreen() {
var showFeedback by remember { mutableStateOf(false) }
Button(onClick = { showFeedback = true }) {
Text("Send Feedback")
}
if (showFeedback) {
Dialog(onDismissRequest = { showFeedback = false }) {
Surface(shape = MaterialTheme.shapes.large) {
CutiEFeedbackView(
onDismiss = { showFeedback = false },
onSuccess = { conversationId ->
println("Created: $conversationId")
}
)
}
}
}
}
Conversation API
Categories
| Category | Description |
|---|---|
bug | Bug reports |
feature | Feature requests |
question | Questions |
feedback | General feedback |
other | Other |
Statuses
| Status | Description |
|---|---|
open | New, unassigned |
in_progress | Being worked on |
waiting_user | Waiting for user response |
waiting_admin | Waiting for admin response |
resolved | Issue resolved |
closed | Conversation closed |
Message API
Sender Types
| Type | Description |
|---|---|
user | Message from app user |
admin | Message from support admin |
system | Automated system message |
Push Notifications
iOS (APNs)
import UserNotifications
import CutiE
// 1. Request permission (in app startup)
CutiE.shared.pushNotifications.requestPermission { granted in
print("Push notifications \(granted ? "enabled" : "denied")")
}
// 2. In AppDelegate, forward the device token to CutiE
func application(_ application: UIApplication,
didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
CutiE.shared.pushNotifications.didRegisterForRemoteNotifications(withDeviceToken: deviceToken)
}
func application(_ application: UIApplication,
didFailToRegisterForRemoteNotificationsWithError error: Error) {
CutiE.shared.pushNotifications.didFailToRegisterForRemoteNotifications(withError: error)
}
Android (FCM)
import com.google.firebase.messaging.FirebaseMessaging
import com.cutie.sdk.CutiE
FirebaseMessaging.getInstance().token.addOnCompleteListener { task ->
if (task.isSuccessful) {
CutiE.getInstance(context).registerPushToken(task.result) { result ->
result.onSuccess {
println("Push token registered")
}
}
}
}
Need help? Email us at [email protected] or check out the full SDK code on GitHub.