SDK Functionality
Before proceeding, you need to configure the SDK for your application. The detailed setup guide is available here.
Working with subscription statuses
Changing subscription status
AltcraftSDK
// Singleton, the entry point to the SDK
└── static let shared: AltcraftSDK
// Push subscription managment
└── pushSubscriptionFunctions: PublicPushSubscriptionFunctions
// Subscribe (status = SUBSCRIBED)
├── pushSubscribe(
│ sync: Bool = true,
│ profileFields: [String: Any?]? = nil,
│ customFields: [String: Any?]? = nil,
│ cats: [CategoryData]? = nil,
│ replace: Bool? = nil,
│ skipTriggers: Bool? = nil
│ ): Void
// Unsubscribe (status = UNSUBSCRIBED)
├── pushUnSubscribe(
│ sync: Bool = true,
│ profileFields: [String: Any?]? = nil,
│ customFields: [String: Any?]? = nil,
│ cats: [CategoryData]? = nil,
│ replace: Bool? = nil,
│ skipTriggers: Bool? = nil
│ ): Void
// Suspend (status = SUSPENDED)
└── pushSuspend(
sync: Bool = true,
profileFields: [String: Any?]? = nil,
customFields: [String: Any?]? = nil,
cats: [CategoryData]? = nil,
replace: Bool? = nil,
skipTriggers: Bool? = nil
): Void
Subscription status change functions:
func pushSubscribe()— subscribes to push notifications;func pushUnSubscribe()— unsubscribes from push notifications;func pushSuspend()— suspends the push subscription (no notifications are delivered, but no unsubscribe event is created in the user’s profile);func unSuspendPushSubscription()— used to implementLogIn/LogOuttransitions.
All functions in this group have the same signature and parameters:
sync: Bool
Default: true
Required: No
Description: A flag that sets whether the request is executed synchronously.
Successful request execution:
On success, these functions produce an event with code 230, 231 or 232, containing an event.value defined by the sync flag:
If sync == true
ResponseWithHttpCode
├─ httpCode: 200
└─ response
├─ error: 0
├─ errorText: ""
└─ profile
├─ id: "your id"
├─ status: "subscribed"
├─ isTest: false
└─ subscription
├─ subscriptionId: "your subscriptionId"
├─ hashId: "c52b28d2"
├─ provider: "ios-apns"
├─ status: "subscribed"
├─ fields
│ ├─ _os_ver: {"raw":"18.6.2","ver":"[\"18.0\", \"6.0\", \"2.0\"]"}
│ ├─ _device_type: "mob"
│ ├─ _ad_track: false
│ ├─ _device_name: "iPhone"
│ ├─ _os_language: "en"
│ ├─ _os_tz: "+0300"
│ ├─ _os: "IOS"
│ └─ _device_model: "iPhone14,7"
└─ cats
└─ [ { name: "developer_news", title: "dev_news", steady: false, active: false } ]
For synchronous requests, the event.value["response_with_http_code"] contains:
-
httpCode – transport-level status code;
-
Response – a public struct containing:
-
error: Int?— internal server error code (0 if no errors), -
errorText: String?— error text (empty string if no errors), -
profile: ProfileData?— profile data if the request is successful:- profile info (ProfileData)
- subscription (SubscriptionData)
- subscription categories (CategoryData)
- if the request fails,
profile = nil
-
Data structures
public struct Response {
let error: Int? // internal error code
let errorText: String? // error text
let profile: ProfileData?
}
public struct ProfileData {
let subscription: SubscriptionData?
let cats: [CategoryData]?
}
public struct SubscriptionData {
// Subscription Data
}
public struct CategoryData {
// Subscription Category Data
}
If sync == false
ResponseWithHttpCode
├─ httpCode: Int?
└─ response: Response?
├─ error: Int?
├─ errorText: String?
└─ profile: ProfileData? = nil
For asynchronous requests, event.value["response_with_http_code"] contains:
-
httpCode – transport-level status code;
-
Response – a public struct containing:
error: Int?— internal server error code (0 if no errors),errorText: String?— error text (empty string if no errors),profile: ProfileData?— profile data, alwaysnilfor async requests.
Failed request execution:
If a request in this group fails, an event with one of the following codes is created:
Operations without automatic retry on the SDK side:
- 430 – notification subscription;
- 431 — subscription suspension;
- 432 — unsubscription.
Operations with automatic retry on the SDK side:
- 530 – notification subscription;
- 531 — subscription suspension;
- 532 — unsubscription.
Event contents:
- only
httpCodeif the Altcraft server was unavailable; erroranderrorTextif the server returned an error.
Retrieving event values
AltcraftSDK.shared.eventSDKFunctions.subscribe { event in
let codes: Set<Int> = [
230, 231, 232,
430, 431, 432,
531, 532, 533
]
guard let code = event.eventCode, codes.contains(code) else { return }
guard let responseWithHttp = event.value?["response_with_http_code"] as? ResponseWithHttp else { return }
let httpCode = responseWithHttp.httpCode
let response = responseWithHttp.response
let error = response?.error
let errorText = response?.errorText
let profile = response?.profile
let profileId = profile?.id
let profileStatus = profile?.status
let profileIsTest = profile?.isTest
let subscription = profile?.subscription
let subscriptionId = subscription?.subscriptionId
let hashId = subscription?.hashId
let provider = subscription?.provider
let subscriptionStatus = subscription?.status
let fields = subscription?.fields
let cats = subscription?.cats
let firstCat = cats?.first
let catName = firstCat?.name
let catTitle = firstCat?.title
let catSteady = firstCat?.steady
let catActive = firstCat?.active
}
The fields inside subscription may include your custom subscription fields. They are of type [String: JSONValue]?. The public enum JSONValue provides helpers to simplify field value extraction:
public var stringValue: String? {
if case let .string(value) = self { return value }
return nil
}
/// Returns the numeric value if case is `.number`, otherwise `nil`.
public var numberValue: Double? {
if case let .number(value) = self { return value }
return nil
}
/// Returns the bool value if case is `.bool`, otherwise `nil`.
public var boolValue: Bool? {
if case let .bool(value) = self { return value }
return nil
}
/// Returns the object dictionary if case is `.object`, otherwise `nil`.
public var objectValue: [String: JSONValue]? {
if case let .object(value) = self { return value }
return nil
}
/// Returns the array if case is `.array`, otherwise `nil`.
public var arrayValue: [JSONValue]? {
if case let .array(value) = self { return value }
return nil
}
Example of extracting the field "_device_name":
AltcraftSDK.shared.eventSDKFunctions.subscribe { event ->
if event.eventCode == 230 {
if let responseWithHttp = event.value?["response_with_http_code"] as? ResponseWithHttp {
let response = responseWithHttp.response
let profile = response?.profile
let subscription = profile?.subscription
// extract fields?["_device_name"] as a string value
if let deviceName = subscription?.fields?["_device_name"]?.stringValue {
print(deviceName)
}
}
}
}
profileFields: [String: Any?]?
Default: nil
Required: No
Description: A dictionary containing profile fields.
The parameter may include system fields (e.g., _fname — first name, _lname — last name) and optional fields (manually created in the platform UI). Allowed JSON-compatible value types:
- String
- Bool
- Numbers
nil- Objects
[String: Any] - Arrays
If an invalid optional field is passed, the request fails:
SDK error: 430
http code: 400
error: 400
errorText: Platform profile processing error: with field "field_name": Incorrect field
customFields: [String: Any?]?
Default: nil
Required: No
Description: A dictionary containing subscription fields.
The parameter may include system fields (e.g., _device_model — device model, _os — OS), as well as optional ones (manually created in the platform UI). Allowed types:
- String
- Bool
- Int
- Float
- Double
nil
If an invalid optional field is passed, the request fails:
SDK error: 430
http code: 400
error: 400
errorText: Platform profile processing error: field "field_name" is not valid: failed convert custom field
Nested objects, arrays, and collections are not allowed.
Most system subscription fields are automatically collected by the SDK and added to push requests. These include: "_os", "_os_tz", "_os_language", "_device_type", "_device_model", "_device_name", "_os_ver", "_ad_track", "_ad_id".
cats: [CategoryData]?
Default: nil
Required: No
Description: Subscription categories.
Category structure:
public struct CategoryData: Codable {
public var name: String?
public var title: String?
public var steady: Bool?
public var active: Bool?
}
When sending a push request with categories, use only name (category name) and active (category active status). Other fields are not used in request processing. The title and steady fields are populated when retrieving subscription info.
Request example:
let cats: [CategoryData] = [CategoryData(name: "football", title: nil, steady: nil, active: true)]
Response example:
[ { name: "developer_news", title: "dev_news", steady: false, active: false } ]
Categories used in the request must be created beforehand and added to the resource in the Altcraft platform. If a category not present in the resource is used, the request returns an error:
SDK error: 430
http code: 400
error: 400
errorText: Platform profile processing error: field "subscriptions.cats" is not valid: category not found in resource
replace: Bool?
Default: nil
Required: No
Description: When enabled, all subscriptions of other profiles with the same push token in the current database are set to unsubscribed after a successful request.
skipTriggers: Bool?
Default: nil
Required: No
Description: When enabled, the profile containing this subscription will be ignored by mailing and scenario triggers.
Request examples
Example: subscribing to push notifications
Minimal working call:
AltcraftSDK.shared.pushSubscriptionFunctions.pushSubscribe()
Passing all available parameters:
AltcraftSDK.shared.pushSubscriptionFunctions.pushSubscribe(
sync: true,
profileFields: ["_fname":"Andrey", "_lname":"Pogodin"],
customFields: ["developer":true],
cats: [CategoryData(name: "developer_news", active: true)],
replace: false,
skipTriggers: false
)
For pushSubscribe, pushSuspend, and pushUnSubscribe, the SDK automatically retries the request if the HTTP status code is in the 500..599 range. No retry occurs if the code is outside this range.
Function unSuspendPushSubscription()
func unSuspendPushSubscription() is designed for LogIn / LogOut transitions. It works as follows:
- searches for subscriptions with the same push token as the current one that do not belong to the profile referenced by the current JWT;
- changes the status of the found subscriptions from
subscribedtosuspended; - changes the status of the subscriptions in the profile referenced by the current JWT from
suspendedtosubscribed(if that profile exists and contains subscriptions); - returns a
ResponseWithHttpCode?whereresponse.profileis the current profile referenced by the JWT (if the profile does not exist,response.profileisnil).
Example:
AltcraftSDK.shared.pushSubscriptionFunctions.unSuspendPushSubscription(completion: @escaping (ResponseWithHttp?) -> Void)
Recommended LogIn / LogOut flow
LogIn flow:
- An anonymous user opens the app. The user has
JWT_1, pointing to database #1Anonymous; - The user subscribes to push; a profile is created in #1Anonymous;
- The user registers and receives
JWT_2, pointing to #2Registered; - Call
unSuspendPushSubscription()— the anonymous subscription in #1Anonymous is suspended; - The SDK searches for a profile in #2Registered to restore the subscription;
- Since a subscription with this push token does not exist in #2Registered,
unSuspendPushSubscription()returnsnil; - After receiving
nil, callpushSubscribe()to create a new profile in #2Registered.
LogOut flow:
- The user logs out in the app (
LogOut); - The user receives
JTW_1, pointing to #1Anonymous; - Call
unSuspendPushSubscription(), which suspends the subscription in #2Registered and sets the status in #1Anonymous tosubscribed; - The request returns
#1Anonymous != nil— the subscription already exists, no new one is required.
Example implementation:
func logIn() {
JWTManager.shared.setRegJWT()
// JWT is set for an authorized user
AltcraftSDK.shared.pushSubscriptionFunctions.unSuspendPushSubscription { result in
if result?.httpCode == 200, result?.response?.profile?.subscription == nil {
AltcraftSDK.shared.pushSubscriptionFunctions.pushSubscribe(
// specify the required parameters
)
}
}
}
func logOut() {
JWTManager.shared.setAnonJWT()
// JWT is set for an anonymous user
AltcraftSDK.shared.pushSubscriptionFunctions.unSuspendPushSubscription { result in
if result?.httpCode == 200, result?.response?.profile?.subscription == nil {
AltcraftSDK.shared.pushSubscriptionFunctions.pushSubscribe(
// specify the required parameters
)
}
}
}
Requesting subscription status
AltcraftSDK
// Singleton, the entry point to the SDK
└── static let shared: AltcraftSDK
// Subscription managment
└── pushSubscriptionFunctions: PublicPushSubscriptionFunctions
// Last profile subscription status
├── getStatusOfLatestSubscription(
│ completion: @escaping (ResponseWithHttp?) -> Void
│ ): Void
// Subscription status corresponding to the current token/provider
├── getStatusForCurrentSubscription(
│ completion: @escaping (ResponseWithHttp?) -> Void
│ ): Void
// Status of the latest subscription for the provider (if nil — the current one is used)
└── getStatusOfLatestSubscriptionForProvider(
provider: String? = nil,
completion: @escaping (ResponseWithHttp?) -> Void
): Void
Subscription status functions:
func getStatusOfLatestSubscription()— the last subscription status in the profile;func getStatusOfLatestSubscriptionForProvider()— the subscription status for the current token/provider;func getStatusForCurrentSubscription()— the latest subscription status by provider. Ifnilis specified, the current one is used.
public func getStatusOfLatestSubscription(completion: @escaping (ResponseWithHttp?) -> Void): Void
Retrieves the status of the profile’s latest subscription. The completion receives a ResponseWithHttp? containing response?.profile?.subscription — the most recently created subscription in the profile. If no such subscription exists, nil is passed.
Example:
// Last profile subscription status
AltcraftSDK.shared.pushSubscriptionFunctions.getStatusOfLatestSubscription(completion: @escaping (ResponseWithHttp?) -> Void)
public func getStatusForCurrentSubscription(completion: @escaping (ResponseWithHttp?) -> Void): Void
Retrieves the subscription status for the current token/provider. The completion receives a ResponseWithHttp? containing response?.profile?.subscription — the subscription found by the current push token and provider. If no such subscription exists, nil is passed.
Example:
// Subscription status corresponding to the current token/provider
AltcraftSDK.shared.pushSubscriptionFunctions.getStatusForCurrentSubscription(completion: @escaping (ResponseWithHttp?) -> Void)
public func getStatusOfLatestSubscriptionForProvider(provider: String? = nil, completion: @escaping (ResponseWithHttp?) -> Void): Void
Retrieves the latest subscription status by provider. The completion receives a ResponseWithHttp? containing response?.profile?.subscription — the most recently created subscription for the specified push provider. If no provider is specified, the current token’s provider is used. If no such subscription exists, nil is passed.
Example:
// Status of the latest subscription for the provider (if nil — the current one is used)
AltcraftSDK.shared.pushSubscriptionFunctions.getStatusOfLatestSubscriptionForProvider(provider: String? = nil, completion: @escaping (ResponseWithHttp?) -> Void)
Below is an example of extracting profile, subscription, and category data from the status response. This approach applies to all status-retrieval functions:
Data from status-retrieval functions
AltcraftSDK.shared.pushSubscriptionFunctions.getStatusForCurrentSubscription{ responseWithHttp in
// HTTP code
let httpCode = responseWithHttp?.httpCode
// Response
let response = responseWithHttp?.response
let error = response?.error
let errorText = response?.errorText
// Profile
let profile = response?.profile
let profileId = profile?.id
let profileStatus = profile?.status
let profileIsTest = profile?.isTest
// Subscription
let subscription = profile?.subscription
let subscriptionId = subscription?.subscriptionId
let hashId = subscription?.hashId
let provider = subscription?.provider
let subscriptionStatus = subscription?.status
// Fields (dictionary [String: JSONValue])
let fields = subscription?.fields
// Cats (array of CategoryData)
let cats = subscription?.cats
// CategoryData (every element of cats array)
let firstCat = cats?.first
let catName = firstCat?.name
let catTitle = firstCat?.title
let catSteady = firstCat?.steady
let catActive = firstCat?.active
}
On a successful request, an event with code 234 is created. On error — an event with code 434.
Provider push token management
AltcraftSDK
// Singleton, the entry point to the SDK