Public SDK API
The SDK is built from modules: the required Core and the optional Push, Target, Profile, In-App. Each module is connected as a separate dependency and is exposed through the corresponding property of the AltcraftSDK.shared object — the property becomes available in code once the module is linked:
AltcraftSDK.shared // Core: initialization, authentication, events, clearing
AltcraftSDK.shared.authFunctions // Core: user authentication
AltcraftSDK.shared.eventSDKFunctions // Core: subscription to SDK events
AltcraftSDK.shared.backgroundTasks // Core: background tasks
AltcraftSDK.shared.push // Push: subscriptions, tokens, notifications
AltcraftSDK.shared.target // Target: sending goals
AltcraftSDK.shared.profile // Profile: profile fields
AltcraftSDK.shared.inApp // In-App: campaigns and subscriptions
The Push, Target, Profile and InApp facade classes are not available in the Notification Service Extension: the extension runs in a separate process. To call the API from the NSE, use the AltcraftNSE class.
Core (required module)
class AltcraftSDK
AltcraftSDK
// Singleton — the SDK entry point
├─ static let shared: AltcraftSDK
// SDK initialization and configuration setup (completion is called on main)
├─ func initialization(
│ configuration: AltcraftConfiguration?,
│ completion: (@Sendable (Bool) -> Void)? = nil
│ ): Void
// Full cleanup of SDK data (cache, DB, settings), then calls completion
├─ func clear(completion: (() -> Void)? = nil): Void
// Set up the App Group and initialize Core Data under the shared container
├─ func setAppGroup(groupName: String?): Void
// Register a JWT provider for obtaining tokens
├─ func setJWTProvider(provider: JWTInterface): Void
// Stream of SDK events (one active subscriber)
├─ let eventSDKFunctions: SDKEvents
// Access to user authentication
├─ let authFunctions: AuthAPI
// Registration of periodic background tasks (BGAppRefreshTask)
└─ let backgroundTasks: BackgroundTask
// Optional modules (visible when the corresponding module is linked):
├─ var push: Push // AltcraftPush
├─ var target: Target // AltcraftTarget
├─ var profile: Profile // AltcraftProfile
└─ var inApp: InApp // AltcraftInApp
class AuthAPI
AuthAPI
// User authentication
├─ func authenticate(): Void
// User logout (restores the anonymous session)
└─ func logOut(): Void
// ObjC-compatible wrappers:
├─ func authenticateObjC(): Void
└─ func logOutObjC(): Void
class SDKEvents
SDKEvents
// Subscribe to SDK events (replaces the existing subscriber)
├─ func subscribe(callback: @escaping (Event) -> Void): Void
// Compatibility overload: the queue parameter is ignored,
// the callback is always delivered on the main thread
├─ func subscribe(
│ on queue: DispatchQueue = .main,
│ callback: @escaping (Event) -> Void
│ ): Void
// Unsubscribe from SDK events (the callback remains assigned, delivery stops)
└─ func unsubscribe(): Void
// ObjC-compatible wrappers:
├─ func subscribeObjC(_ callback: @escaping (Event) -> Void): Void
└─ func unsubscribeObjC(): Void
class Event — the SDK event model
Event
// Base SDK event (universal telemetry)
public let id: UUID // unique event identifier
public let function: String // name of the SDK function that produced the event
public let event: (any SDKEvent)? // typed event (see CoreEvents and the module event enums)
public let message: String? // text description
public let value: [String: Any]? // additional data (nil values are filtered out)
public let date: Date // event time
public var objcValue: NSDictionary? // ObjC access to value
// Constructor
└─ init(
function: String,
event: (any SDKEvent)? = nil,
message: String? = nil,
value: [String: Any?]? = nil,
date: Date = Date()
)
// Error event without automatic retry (inherits Event)
ErrorEvent : Event
// Request error event with automatic retry (inherits ErrorEvent)
RetryEvent : ErrorEvent
Events are compared by id; Event, ErrorEvent and RetryEvent accept the same set of constructor parameters.
enum CoreEvents — Core module events
CoreEvents
// General SDK events
├─ configSet // SDK configuration is installed.
├─ sdkCleared // SDK data has been cleared
├─ initAwait // waiting for SDK initialization to complete
├─ userLogOut // User logged out. Anonymous session started
├─ backgroundTaskRegister // SDK background task is registered
├─ backgroundTaskCompleted // SDK background task completed
// State and environment errors
├─ configIsNotSet // the configuration is not set
├─ coreDataError // error in CoreData. Re-initialize the SDK.
├─ errorLoadModelInCoreData // failed to load model from framework.
├─ appGroupIsNotSet // App Group name was not set.
├─ contextIsUnavailable // core data context is unavailable
├─ invalidCoreDataEntityName // the coreData entity name is not valid
├─ entityNotFoundByID // entity not found by ID
├─ coreDataModelNotFoundInBundle // Core Data model was not found in any bundle
├─ coreDataModelMissingEntity // Core Data model is missing the required entity; the model did not load
├─ sdkInitWaitingExpired // SDK initialization timeout has expired
├─ notAuthenticatedError // user is not authenticated
// Invalid values
├─ invalidUrlValue // invalid apiUrl value - empty or null.
├─ invalidRTokenValue // invalid resource token value - resource token is empty.
├─ nonJsonObject // non-json object has been provided
├─ fieldsIsObjects // invalid values: not all values are primitives
// Missing SDK state and environment issues
├─ configIsNil // config data is nil
├─ userTagIsNil // userTag is null. It is impossible to identify the user
├─ permissionDenied // notification permission denied.
├─ backgroundTaskExpired // SDK background task expired
// Authentication errors
├─ jwtIsNil // JWT token is nil
├─ jwtParsingError // JWT parsing error
├─ externalAuthDataIsNil // external auth data is nil
├─ internalAuthDataIsNil // internal auth data is nil
// Request creation and processing errors
├─ failedCreateRequest // Failed to create request.
├─ failedProcessingResponse // Failed processing the response
// Invalid requests and responses
├─ responseDataIsNull // response data is null
├─ invalidRequestUrl // invalid request url
├─ invalidResponseFormat // invalid response format
// Successful / failed API requests
├─ authenticateSuccessful // successful request: profile/authenticate
└─ authenticateFailed // failed request: profile/authenticate
Each event is an enum case with a string message: var message: String { get }.
actor BackgroundTask
BackgroundTask
// Register an SDK background task (BGAppRefreshTask)
├─ func registerBackgroundTask(): Void
// Schedule a retry of failed requests
├─ func scheduleRetry(): Void
// Schedule a periodic refresh if needed
├─ func scheduleRefreshIfNeeded(): Void
// Cancel the scheduled task
└─ func cancelScheduled(): Void
class AltcraftConfiguration
// Altcraft SDK configuration class: API URL, resource token, app details
// and the logging flag. Created only via the Builder.
// ObjC-compatible: AltcraftConfiguration / AltcraftConfiguration_Builder.
├─ @objc(AltcraftConfiguration_Builder) public final class Builder
│ // All base parameters are set in the initializer
│ ├─ init(
│ │ apiUrl: String, // API URL (required)
│ │ rToken: String? = nil, // resource token (optional)
│ │ appInfo: AppInfo? = nil, // app metadata (optional)
│ │ enableLogging: Bool? = nil // logging flag (optional)
│ │ )
│ // ObjC variant of the initializer (AppInfoObjC)
│ ├─ init(
│ │ apiUrl: String,
│ │ rToken: String?,
│ │ appInfoObjC: AppInfoObjC?,
│ │ enableLogging: Bool
│ │ )
│ // Set the app metadata (a repeated call replaces the value)
│ ├─ @discardableResult func setAppInfo(_ info: AppInfo?) -> Builder
│ // ObjC variant of setting the metadata
│ ├─ @discardableResult func setAppInfo(_ dto: AppInfoObjC?) -> Builder
│ // Module configurations are added with the pushConfig() / inAppConfig() methods
│ // Build a valid configuration (nil if apiUrl is empty)
│ └─ func build() -> AltcraftConfiguration?
Push (optional module)
class Push
Push
// Access to the push token API
├─ var token: TokenAPI
// Access to the push subscription and status API
├─ var subscription: SubscriptionAPI
// Access to push events (delivery, opening)
├─ var pushEvents: EventAPI
// Access to receiving and handling push notifications
└─ var notificationManager: NotificationManager
class TokenAPI
TokenAPI
// Register the Apple Push Notification service provider (nil — remove)
├─ func setAPNSTokenProvider(_ provider: APNSInterface?): Void
// Register the Firebase Cloud Messaging provider (nil — remove)
├─ func setFCMTokenProvider(_ provider: FCMInterface?): Void
// Register the Huawei Mobile Services provider (nil — remove)
├─ func setHMSTokenProvider(_ provider: HMSInterface?): Void
// Asynchronously get the current push token (completion is optional)
├─ func getToken(completion: (@Sendable (TokenData?) -> Void)? = nil): Void
// ObjC variant of getting the token
├─ func getPushTokenObjC(_ completion: ((TokenDataObjC?) -> Void)? = nil): Void
// Save the token manually (String for FCM/HMS, Data for APNs)
├─ func setToken(provider: String, pushToken: Any?): Void
// Apply the new provider priority and initiate a token update
├─ func changeProviderPriority(_ list: [String]): Void
// Force a token update (detect the provider → delete (except APNs) → request a new one)
├─ func forcedTokenUpdate(completion: (@Sendable () -> Void)? = nil): Void
// Delete the token of the selected provider and call the completion
└─ func deleteToken(
provider: String,
completion: (@Sendable () -> Void)? = nil
): Void
class SubscriptionAPI
SubscriptionAPI
// Subscribe (status = SUBSCRIBED)
├─ func subscribe(
│ sync: Bool = true,
│ profileFields: [String: Any?]? = nil,
│ customFields: [String: Any?]? = nil,
│ cats: [CategoryData]? = nil,
│ replace: Bool? = nil,
│ skipTriggers: Bool? = nil
│ ): Void
// Unsubscribe (status = UNSUBSCRIBED)
├─ func unsubscribe(
│ sync: Bool = true,
│ profileFields: [String: Any?]? = nil,
│ customFields: [String: Any?]? = nil,
│ cats: [CategoryData]? = nil,
│ replace: Bool? = nil,
│ skipTriggers: Bool? = nil
│ ): Void
// Suspend (status = SUSPENDED)
├─ func suspend(
│ sync: Bool = true,
│ profileFields: [String: Any?]? = nil,
│ customFields: [String: Any?]? = nil,
│ cats: [CategoryData]? = nil,
│ replace: Bool? = nil,
│ skipTriggers: Bool? = nil
│ ): Void
// Change the status of the subscription specified in the JWT from suspended to subscribed;
// the remaining subscriptions with this push token change their status to suspended
├─ func unSuspend(
│ completion: @escaping @Sendable (
│ ResponseModel.ResponseWithHttpCode<ResponseModel.ResponseWithProfile>?
│ ) -> Void
│ ): Void
// Add a profile action field (set/incr/...)
├─ func actionField(key: String) -> ActionFieldBuilder
// Status of the profile's latest subscription
├─ func latest(
│ completion: @escaping @Sendable (
│ ResponseModel.ResponseWithHttpCode<ResponseModel.ResponseWithProfile>?
│ ) -> Void
│ ): Void
// Status of the subscription matching the current token and provider
├─ func current(
│ completion: @escaping @Sendable (
│ ResponseModel.ResponseWithHttpCode<ResponseModel.ResponseWithProfile>?
│ ) -> Void
│ ): Void
// Status of the latest subscription for the provider (if nil — the current one is used)
└─ func latestForProvider(
provider: String? = nil,
completion: @escaping @Sendable (
ResponseModel.ResponseWithHttpCode<ResponseModel.ResponseWithProfile>?
) -> Void
): Void
Each method has an ObjC overload that takes NSDictionary / CategoryDataObjC and returns ResponseWithHttpCodeObjC.
class EventAPI
EventAPI
// Register the delivery of an Altcraft push (fires the delivery event)
├─ func deliveryEvent(from request: UNNotificationRequest): Void
// Register the opening of an Altcraft push (fires the open event)
└─ func openEvent(from request: UNNotificationRequest): Void
class NotificationManager
// Manager of incoming push notifications: registration, display, click handling
NotificationManager
// Singleton (entry point)
├─ static let shared: NotificationManager
// Push registration (delegate + requestAuthorization + registerForRemoteNotifications)
├─ func registerForPushNotifications(
│ for application: UIApplication,
│ completion: ((_ granted: Bool, _ error: Error?) -> Void)? = nil
│ ): Void
// Controls push notification handling in the foreground (true — handled by the app)
├ ─ var customPushProcessing: Bool
// Controls notification click handling (true — handled by the app)
├─ var customClickProcessing: Bool
// Callback for custom foreground notification handling
├─ var onForegroundNotification: (
│ (UNNotification, @escaping (UNNotificationPresentationOptions) -> Void) -> Void
│ )?
// Callback for custom notification click handling
├─ var onNotificationClick: (
│ (UNNotificationResponse, @escaping () -> Void) -> Void
│ )?
// NotificationCenter events published by the SDK
├─ Notification.Name.altcraftPushWillPresent // the notification is shown in the foreground
└─ Notification.Name.altcraftPushDidReceive // the notification / action is tapped
Push module configuration
// The configuration is added to the Builder with the pushConfig() method:
└─ func AltcraftConfiguration.Builder.pushConfig(
providerPriority: [String] = [], // Push provider priority (optional)
pushReceiverModules: [String] = [], // Package prefixes with custom receivers (optional)
pushChannelName: String? = nil, // Push notification channel name (optional)
pushChannelDescription: String? = nil // Push notification channel description (optional)
) -> Self
Target (optional module)
class Target
Target
// Access to the goal registration API
├─ var target: TargetAPI
// Send a goal (a target event) to the server
└─ func sendTarget(
sid: String,
altcraftClientID: String = "",
eventName: String,
sendMessageId: String? = nil,
payload: [String: Any?]? = nil,
matching: [String: Any?]? = nil,
matchingType: String? = nil,
profileFields: [String: Any?]? = nil,
subscription: (any Subscription)? = nil,
utm: UTM? = nil
): Void
class TargetAPI
TargetAPI
// Send a goal (a target event) to the server
└─ func sendTarget(
sid: String,
altcraftClientID: String = "",
eventName: String,
sendMessageId: String? = nil,
payload: [String: Any?]? = nil,
matching: [String: Any?]? = nil,
matchingType: String? = nil,
profileFields: [String: Any?]? = nil,
subscription: (any Subscription)? = nil,
utm: UTM? = nil
): Void
Profile (optional module)
class Profile
Profile
// Access to the profile field update API
├─ var update: UpdateAPI
// Update profile fields
└─ func updateProfileFields(
profileFields: [String: Any?]? = nil,
skipTriggers: Bool? = nil
): Void
class UpdateAPI
UpdateAPI
// Update profile fields
└─ func updateProfileFields(
profileFields: [String: Any?]? = nil,
skipTriggers: Bool? = nil
): Void
In-App (optional module)
class InApp
InApp
// Subscribe to the app lifecycle for automatic In-App display
├─ func registerLifecycleTracking(): Void
// Set the current screen marker (used when filtering In-App notifications)
├─ func setScreen(screen: String): Void
// Trigger a custom In-App campaign by name
├─ func trigger(name: String): Void
// Request the available In-App placements
├─ func getPlacements(): Void
// Configure the In-App notification animation
├─ func animation(_ block: @escaping @MainActor (InAppAnimator) -> Void): Void
// Manage In-App notification subscriptions
└─ var subscription: SubscribeAPI
class SubscribeAPI (In-App)
SubscribeAPI
// Subscribe to In-App notifications (status = SUBSCRIBED)
├─ func subscribe(
│ sync: Bool = true,
│ profileFields: [String: Any?]? = nil,
│ customFields: [String: Any?]? = nil,
│ cats: [CategoryData]? = nil,
│ replace: Bool? = nil,
│ skipTriggers: Bool? = nil
│ ): Void
// Unsubscribe from In-App notifications (status = UNSUBSCRIBED)
├─ func unSubscribe(
│ sync: Bool = true,
│ profileFields: [String: Any?]? = nil,
│ customFields: [String: Any?]? = nil,
│ cats: [CategoryData]? = nil,
│ replace: Bool? = nil,
│ skipTriggers: Bool? = nil
│ ): Void
// In-App notification subscription status
└─ func getSubscriptionStatus(
completion: @escaping @Sendable (
ResponseModel.ResponseWithHttpCode<ResponseModel.ResponseWithProfile>?
) -> Void
): Void
protocol InAppAnimator
InAppAnimator
// Identifier of the placement the animator belongs to
├─ var companyId: Int { get }
// Apply the block to the In-App view instantly, without running an animation
├─ @MainActor func prepare(_ block: (UIView) -> Void): Void
// Configure and run a UIKit animation for the In-App view
└─ @MainActor func animate(
duration: TimeInterval,
delay: TimeInterval,
options: UIView.AnimationOptions,
animations: @escaping (UIView) -> Void,
completion: ((Bool) -> Void)?
): Void
In-App module configuration
// The configuration is added to the Builder with the inAppConfig() method:
└─ func AltcraftConfiguration.Builder.inAppConfig(
inAppAutoRequest: Bool = true, // Automatic request of In-App placements (optional)
placementsRequestInterval: Measurement<UnitDuration> = 30 minutes,
// Interval of automatic placement requests (optional)
maxPlacements: Int = 500 // Maximum placements in local storage (optional)
) -> Self
Data models
Data Classes (Core)
// App metadata for analytics (if used)
public struct AppInfo: Codable, Sendable {
public var appID: String
public var appIID: String
public var appVer: String
}
// API response wrapper together with the HTTP code
public struct ResponseWithHttpCode<T: ResponseData & Sendable> {
public let httpCode: Int?
public let response: T?
}
// Response containing profile data
public struct ResponseWithProfile: Codable {
public let error: Int?
public let errorText: String?
public let profile: ProfileData?
}
// User profile data
public struct ProfileData: Codable {
public let id: String?
public let status: String?
public let acid: String?
public let isTest: Bool?
public let subscription: SubscriptionData?
}
// The profile's current subscription
public struct SubscriptionData: Codable {
public let subscriptionId: String?
public let hashId: String?
public let provider: String?
public let status: String?
public let fields: [String: JSONValue]?
public let cats: [CategoryData]?
}
// Subscription category (name, title, flags)
public struct CategoryData: Codable {
public var name: String?
public var title: String?
public var steady: Bool?
public var active: Bool?
}
Data Classes (Push)
// Push provider token of the device
public struct TokenData: Codable, Hashable, Sendable {
public let provider: String
public let token: String
}
Data Classes (Target)
// UTM parameter container for goal attribution (all fields are optional)
public struct UTM: Codable {
public let campaign: String?
public let content: String?
public let keyword: String?
public let medium: String?
public let source: String?
public let temp: String?
}
// Base protocol of all subscription types added by a goal
public protocol Subscription {}
// Subscription to the Email channel
public struct EmailSubscription: Subscription, Codable {
public let resourceId: Int
public let email: String
public let status: String?
public let priority: Int?
public let customFields: [String: JSONValue]?
public let cats: [String]?
public let channel: String = "email"
}
// Subscription to the SMS channel
public struct SmsSubscription: Subscription, Codable {
public let resourceId: Int
public let phone: String
public let status: String?
public let priority: Int?
public let customFields: [String: JSONValue]?
public let cats: [String]?
public let channel: String = "sms"
}
// Subscription to the push channel
public struct PushSubscription: Subscription, Codable {
public let resourceId: Int
public let provider: String
public let subscriptionId: String
public let status: String?
public let priority: Int?
public let customFields: [String: JSONValue]?
public let cats: [String]?
public let channel: String = "push"
}
// Subscription with cc_data (Telegram, WhatsApp, Viber, Notify)
public struct CcDataSubscription: Subscription, Codable {
public let resourceId: Int
public let channel: String
public let ccData: [String: JSONValue]
public let status: String?
public let priority: Int?
public let customFields: [String: JSONValue]?
public let cats: [String]?
}
// Builder of action field operations (set/unset/incr/add/delete/upsert) on a
// profile field. The result is an entry for the profileFields dictionary.
public struct ActionFieldBuilder {
public init(key: String)
public func set(value: Any?) -> [String: Any?]
public func unset(value: Any?) -> [String: Any?]
public func incr(value: Any?) -> [String: Any?]
public func add(value: Any?) -> [String: Any?]
public func delete(value: Any?) -> [String: Any?]
public func upsert(value: Any?) -> [String: Any?]
}
Constants
// Push module constants
└─ enum PushConstants
// Push notification providers
├─ enum ProviderName
│ ├─ static let apns = "ios-apns"
│ ├─ static let firebase = "ios-firebase"
│ └─ static let huawei = "ios-huawei"
Interfaces
JWTInterface (Core):
JWTInterface
// Access to the current JWT
└─ func getToken() -> String?
// Returns the current JWT or nil
APNSInterface (Push):
APNSInterface
// Contract for obtaining the APNs token
└─ func getToken(completion: @escaping (String?) -> Void)
// Returns the APNs token via the completion or nil
FCMInterface (Push):
FCMInterface
// Contract for FCM token operations (obtaining/revoking)
├─ func getToken(completion: @escaping (String?) -> Void)
│ // Returns the FCM token via the completion or nil
└─ func deleteToken(completion: @escaping (Bool) -> Void)
// Deletes the FCM token; completion(true|false)
HMSInterface (Push):
HMSInterface
// Contract for HMS token operations
├─ func getToken(completion: @escaping (String?) -> Void)
│ // Returns the HMS token via the completion or nil
└─ func deleteToken(completion: @escaping (Bool) -> Void)
// Deletes the HMS token; completion(true|false)
Subscription (Target):
Subscription (protocol)
// Base protocol for all subscription types passed with a goal.
// Polymorphic serialization; the discriminator field is channel.
AltcraftNSE — calling the API from a Notification Service Extension
AltcraftNSE
// Shared (singleton) instance for centralized NSE logic
├─ static let shared: AltcraftNSE
// Set up the App Group and initialize the shared data container
├─ func setAppGroup(groupName: String?): Void
// Register a JWT provider
├─ func setJWTProvider(provider: JWTInterface): Void
// Module extensions (visible when the corresponding module is linked):
// Push:
├─ func isAltcraftPush(_ request: UNNotificationRequest) -> Bool
├─ func handleNotificationRequest(
│ request: UNNotificationRequest,
│ contentHandler: @escaping (UNNotificationContent) -> Void
│ ): Void
├─ func serviceExtensionTimeWillExpire(): Void
// Target:
├─ func sendTarget(...): Void // the same parameters as Target.sendTarget
// Profile:
└─ func updateProfileFields(
profileFields: [String: Any?]? = nil,
skipTriggers: Bool? = nil
): Void