SDK Functionality
You need to set up the SDK for your application first. The detailed instructions are here.
Working with Subscription Statuses
Changing Subscription Status
AltcraftSDK (Flutter)
└─ Push subscription functions
// Subscribe: status = subscribed
├─ static void pushSubscribe({
│ bool? sync,
│ Map<String, dynamic>? profileFields,
│ Map<String, dynamic>? customFields,
│ List<dynamic>? cats,
│ bool? replace,
│ bool? skipTriggers,
│ })
// Suspend: status = suspended
├─ static void pushSuspend({
│ bool? sync,
│ Map<String, dynamic>? profileFields,
│ Map<String, dynamic>? customFields,
│ List<dynamic>? cats,
│ bool? replace,
│ bool? skipTriggers,
│ })
// Unsubscribe: status = unsubscribed
└─ static void pushUnSubscribe({
bool? sync,
Map<String, dynamic>? profileFields,
Map<String, dynamic>? customFields,
List<dynamic>? cats,
bool? replace,
bool? skipTriggers,
})
pushSubscribe()— subscribes to push notifications;pushSuspend()— suspends push subscription (notifications stop arriving, but no unsubscribe event is created in the user profile);pushUnSubscribe()— unsubscribes from push notifications;unSuspendPushSubscription()— used for creatingLogInandLogOuttransitions.
The functions pushSubscribe(), pushSuspend(), and pushUnSubscribe() have the same signature.
sync: bool?
Default: null
Required: No
Description: Flag that sets synchronous execution of the request.
Successful request execution:
Upon successful execution, an SDK event with code 230, 231, or 232 will be created, containing event.value determined by the synchronization flag:
If sync == true
ResponseWithHttpCode
├─ httpCode: 200
└─ response
├─ error: 0
├─ errorText: ""
└─ profile
├─ id: "000000000000000000000000"
├─ status: "subscribed"
├─ isTest: false
└─ subscription
├─ subscriptionId: "provider-subscription-id"
├─ hashId: "7f31a9c4"
├─ provider: "android-firebase"
├─ status: "subscribed"
├─ fields
│ ├─ _os: "Android"
│ ├─ _os_ver: "14"
│ ├─ _device_type: "mob"
│ ├─ _device_model: "Pixel 7"
│ └─ _app_ver: "1.0.0"
└─ cats
└─ [ { name: "developer_news", active: true } ]
For a synchronous request, the event value event.value under the key response_with_http_code provides:
httpCode— transport response code;response— response data containing:error— internal server error code (0 if no errors);errorText— error text (empty string if no errors);profile— profile and subscription data if the request is successful. If the request fails, onlyprofile = nullwill be returned.
If sync == false
ResponseWithHttpCode
├─ httpCode: int?
└─ response: Map<String, dynamic>?
├─ error: int?
├─ errorText: String?
└─ profile: null // always null for async request
For an asynchronous request, the event value event.value under the key response_with_http_code provides:
httpCode— transport response code;response— response data containing:error— internal server error code (0 if no errors);errorText— error text (empty string if no errors);profile— alwaysnullfor asynchronous requests.
Request execution with an error:
If a request from this group of functions fails, an event will be created with the following codes:
Operations without automatic retry on the SDK side:
- 430 — subscription to notifications;
- 431 — subscription suspension;
- 432 — unsubscription.
Operations with automatic retry on the SDK side:
- 530 — subscription to notifications;
- 531 — subscription suspension;
- 532 — unsubscription.
Event content:
- only
httpCode, if the Altcraft server was unavailable; erroranderrorText, if the server returned an error.
Retrieving event values
import 'package:altcraft_sdk/altcraft_sdk.dart';
final responseCodes = {230, 231, 232, 430, 431, 432, 530, 531, 532};
AltcraftSDK.subscribeToEvents().listen((SdkEvent event) {
if (event.code == null) return;
if (!responseCodes.contains(event.code)) return;
final raw = event.value?['response_with_http_code'];
if (raw == null) return;
final map = raw as Map<String, dynamic>;
final httpCode = map['httpCode'];
final response = map['response'] as Map<String, dynamic>?;
final error = response?['error'] ?? null;
final errorText = response?['errorText'] ?? null;
final profile = response?['profile'] as Map<String, dynamic>?;
final subscription = profile?['subscription'] as Map<String, dynamic>?;
print('httpCode=$httpCode error=$error profileId=${profile?['id']}');
print('subscriptionId=${subscription?['subscription_id']}');
});
profileFields: Map<String, dynamic>?
Default: null
Required: No
Description: Object containing profile fields.
The parameter can accept both system fields (e.g., _fname — first name or _lname — last name) and optional fields (created manually in the platform interface in advance). Allowed structures (JSON-compatible):
- Scalar values:
String,bool,num(int / double),null - Objects:
Map<String, dynamic> - Lists:
List<dynamic>
If an invalid optional field is passed, the request will fail with an error:
SDK error: 430
http code: 400
error: 400
errorText: Platform profile processing error: with field "field_name": Incorrect field
AltcraftSDK.pushSubscribe(
sync: true,
profileFields: const {
'_fname': 'Ivan',
'_lname': 'Petrov',
'_email': 'ivan.petrov@example.com',
},
);
customFields: Map<String, dynamic>?
Default: null
Required: No
Description: Object containing subscription fields.
The parameter can accept both system fields (e.g., _device_model — device model or _os — operating system) and optional fields (created manually in the platform interface in advance). Allowed value types (JSON-compatible, scalars only):
Stringboolnum(int / double)null
If an invalid optional field is passed, the request will fail with an error:
SDK error: 430
http code: 400
error: 400
errorText: Platform profile processing error: field "field_name" is not valid: failed convert custom field
AltcraftSDK.pushSubscribe(
customFields: const {
'source': 'flutter_app',
'build': '100',
},
);
Most system subscription fields are automatically collected by the SDK and added to push requests. These system fields include: "_os", "_os_tz", "_os_language", "_device_type", "_device_model", "_device_name", "_os_ver", "_ad_track", "_ad_id".
cats: List<dynamic>?
Default: null
Required: No
Description: Subscription categories.
The category structure is defined by the CategoryData class:
class CategoryData {
final String? name;
final String? title;
final bool? steady;
final bool? active;
}
When sending a push request with categories, only use the name (category name) and active (category active status) fields. The title and steady fields are not used in request processing — they are populated when retrieving subscription information.
AltcraftSDK.pushSubscribe(
cats: const [
{'name': 'developer_news', 'active': true},
{'name': 'product_updates', 'active': false},
],
);
Categories used in the request must be created and added to the resource in the Altcraft platform in advance. If a category not added to the resource is used in the request, the request will fail with 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: null
Required: No
Description: When this flag is activated, 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: null
Required: No
Description: When this flag is activated, the profile containing this subscription will be ignored in mailing and scenario triggers.
Request implementation examples
Example of a push subscription request
Minimal working setup:
AltcraftSDK.pushSubscribe();
Passing all available parameters:
AltcraftSDK.pushSubscribe(
sync: true,
profileFields: const {'_fname': 'Ivan', '_lname': 'Petrov'},
customFields: const {'source': 'flutter_app'},
cats: const [{'name': 'developer_news', 'active': true}],
replace: false,
skipTriggers: false,
);
For pushSubscribe, pushSuspend, pushUnSubscribe, the SDK provides automatic request retry if the HTTP response code is in the range 500..599. The request is not retried if the response code is outside this range.
unSuspendPushSubscription() function
The function static Future<ResponseWithHttpCode?> unSuspendPushSubscription() is designed for creating LogIn and LogOut transitions. It works as follows:
- searches for subscriptions with the same push token as the current one, not belonging to the profile pointed to by the current JWT token;
- changes the status of found subscriptions from
subscribedtosuspended; - changes the status in subscriptions of the profile pointed to by the current JWT from
suspendedtosubscribed(if the profile pointed to by the JWT exists and contains subscriptions); - returns
ResponseWithHttpCode?, whereresponse?.profileis the current profile pointed to by the JWT (returnsnullif the profile does not exist).
Recommended implementation of LogIn and LogOut transitions
LogIn transition
- An anonymous user enters the application. This user is assigned
JWT_1, pointing to database #1Anonymous; - Push subscription is performed, profile created in database #1Anonymous;
- The user registers and is assigned
JWT_2, pointing to database #2Registered; - Function
unSuspendPushSubscription()is called — the anonymous user's subscription in database #1Anonymous is suspended; - Profile search is performed in database #2Registered to restore the subscription;
- Since no subscription with this push token exists in database #2Registered, the function returns
null; - After receiving
null, you can executepushSubscribe()to create a new profile in database #2Registered.
LogOut transition
- The user logs out from their profile on the application side (
LogOut); - The user is assigned
JWT_1, pointing to database #1Anonymous; - Function
unSuspendPushSubscription()is called, which suspends the subscription in database #2Registered and changes the subscription status in database #1Anonymous tosubscribed; - The request returns profile #1Anonymous != null — the subscription already exists, no new one is needed.
Implementation example:
import 'package:altcraft_sdk/altcraft_sdk.dart';
Future<void> unSuspend(bool logIn) async {
setAuth(logIn);
final ResponseWithHttpCode? result =
await AltcraftSDK.unSuspendPushSubscription();
if (result == null) {
AltcraftSDK.pushSubscribe();
return;
}
final int httpCode = result.httpCode;
final subscription = result.response?['profile']?['subscription'];
if (httpCode == 200 && subscription == null) {
AltcraftSDK.pushSubscribe();
}
}
void logIn() => unSuspend(true);
void logOut() => unSuspend(false);
Requesting Subscription Status
AltcraftSDK
├─ static Future<ResponseWithHttpCode?> getStatusOfLatestSubscription()
├─ static Future<ResponseWithHttpCode?> getStatusForCurrentSubscription()
└─ static Future<ResponseWithHttpCode?> getStatusOfLatestSubscriptionForProvider(
String? provider,
)
Subscription status request functions:
getStatusOfLatestSubscription()— status of the latest profile subscription;getStatusForCurrentSubscription()— status of the subscription for the current token/provider;getStatusOfLatestSubscriptionForProvider()— status of the latest subscription by provider. Ifnullis specified, the provider of the current token is used.
getStatusOfLatestSubscription()
Function to retrieve the status of the latest profile subscription. Returns ResponseWithHttpCode?, containing response?.profile?.subscription — the last created subscription in the profile. If no such subscription exists, null will be returned.
final ResponseWithHttpCode? result =
await AltcraftSDK.getStatusOfLatestSubscription();
getStatusForCurrentSubscription()
Function to retrieve the subscription status for the current token/provider. Returns ResponseWithHttpCode?, containing response?.profile?.subscription — the subscription found by the current push token and provider. If no such subscription exists, null will be returned.
final ResponseWithHttpCode? result =
await AltcraftSDK.getStatusForCurrentSubscription();
getStatusOfLatestSubscriptionForProvider(provider)
Function to retrieve the status of the latest subscription by provider. Returns ResponseWithHttpCode?, containing response?.profile?.subscription — the last created subscription with the specified provider. If the provider is not specified (provider = null), the provider of the current token is used. If no such subscription exists, null will be returned.
final ResponseWithHttpCode? result =
await AltcraftSDK.getStatusOfLatestSubscriptionForProvider('android-firebase');
Below is an example of extracting profile, subscription, and category data from the response of status retrieval functions. This approach applies to all status retrieval functions:
Data from status retrieval functions
import 'package:altcraft_sdk/altcraft_sdk.dart';
Future<void> readStatus() async {
final ResponseWithHttpCode? result =
await AltcraftSDK.getStatusForCurrentSubscription();
if (result == null) return;
final int httpCode = result.httpCode;
final response = result.response;
final int? error = response?['error'] ?? null;
final String? errorText = response?['errorText'] ?? null;
final profile = response?['profile'] as Map<String, dynamic>?;
final subscription = profile?['subscription'] as Map<String, dynamic>?;
final cats = subscription?['cats'] ?? null;
print('httpCode=$httpCode error=$error errorText=$errorText cats=$cats');
}
Managing Provider Push Tokens
AltcraftSDK
├─ static Future<TokenData?> getPushToken()
└─ static Future<void> setPushToken(String provider, String? token)
Functions for working with the provider token in the SDK:
setPushToken()— setting the device push token and provider;getPushToken()— retrieving the current push token.
setPushToken(provider, token)
This function is designed to set the device push token and provider.
- In Flutter,
contextis not passed — token saving and storage is performed on the native SDK side. token: null— means clearing the token for the specified provider.
import 'package:altcraft_sdk/altcraft_sdk.dart';
Future<void> saveFcmToken(String token) async {
await AltcraftSDK.setPushToken('android-firebase', token);
}
Example of passing a token when receiving a new token:
Future<void> onNewToken(String provider, String token) async {
await AltcraftSDK.setPushToken(provider, token);
}
getPushToken()
This function returns the current device push token and provider data as TokenData.
Format of returned data:
TokenData— object with fields:provider: String— provider identifier (e.g.,android-firebase,ios-apns);token: String— push token value.
If the token is unavailable, null will be returned.
import 'package:altcraft_sdk/altcraft_sdk.dart';
Future<void> readPushToken() async {
final TokenData? data = await AltcraftSDK.getPushToken();
final String? provider = data?.provider;
final String? token = data?.token;
print('provider=$provider token=$token');
}
Push Notification Registration and Transmission to SDK
In native code
To set up push notifications in a Flutter project, use the native SDK instructions.
Android:
- Connecting push providers
- Preparing the SDK for push providers
- Passing push notifications to the SDK
iOS:
- Connecting push providers
- Setting up the application AppDelegate
- Preparing NSE
- Working with push notifications
Flutter SDK provides the takePush() method for passing payload to the SDK on Android. On iOS, APNS and rich push processing is typically handled in the native part of the application and the Notification Service Extension.
In Flutter code on Android
If incoming push notifications are handled on the Dart side, pass the payload to the SDK using the takePush() method.
AltcraftSDK.takePush(Map<String, String> message)
where message is the push notification data converted to Map<String, String> format.
FCM (Firebase Cloud Messaging)
Install the required dependencies:
flutter pub add firebase_messaging
Handling push notifications via FCM:
Background push
import 'package:altcraft_sdk/altcraft_sdk.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
@pragma('vm:entry-point')
Future<void> firebaseMessagingBackgroundHandler(RemoteMessage message) async {
final Map<String, String> payload = message.data.map(
(String key, dynamic value) => MapEntry(key, value?.toString() ?? ''),
);
if (payload.isNotEmpty) {
AltcraftSDK.takePush(payload);
}
}
Foreground push
void registerFirebaseForegroundPush() {
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
final Map<String, String> payload = message.data.map(
(String key, dynamic value) => MapEntry(key, value?.toString() ?? ''),
);
if (payload.isNotEmpty) {
AltcraftSDK.takePush(payload);
}
});
}
Registering the background handler is done at application startup:
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/widgets.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
FirebaseMessaging.onBackgroundMessage(firebaseMessagingBackgroundHandler);
runApp(const AppRoot());
}
This approach can be combined with using the native push service FirebaseMessagingService: notifications can be processed natively and simultaneously passed to Flutter/Altcraft SDK for business logic.
Mobile Events
AltcraftSDK
└─ static void mobileEvent({
required String sid,
required String eventName,
String? sendMessageId,
Map<String, dynamic>? payload,
Map<String, dynamic>? matching,
String? matchingType,
Map<String, dynamic>? profileFields,
Map<String, dynamic>? subscription,
Map<String, dynamic>? utm,
})
To register a mobile event, use the mobileEvent() function from AltcraftSDK.
sid: String
Required: Yes
Description: String identifier of the pixel to which mobile events are bound.
eventName: String
Required: Yes
Description: Name of the mobile event.
sendMessageId: String?
Required: No
Description: SMID identifier of the sent message, if the event is related to a specific mailing.
payload: Map<String, dynamic>?
Required: No
Description: Event data — a map with string keys. Values are passed through MethodChannel and serialized by the native SDK:
String— passed as isint/double/bool— converted to string representationMap/List— serialized to a JSON stringnull— key is not passed (field is removed from payload)
It is recommended to pass JSON-compatible values. Non-serializable objects may result in incorrect data.
matching: Map<String, dynamic>?
Required: No
Description: A map for passing matching values with types and identifiers, e.g., {'email': 'ivan.petrov@example.com'}. Serialization follows the same rules as payload.
matchingType: String?
Required: No
Description: Matching type.
profileFields: Map<String, dynamic>?
Required: No
Description: Profile fields. Serialization follows the same rules as payload.
The profileFields parameter is used in scenarios where the profile is identified via JWT authorization and matching.
subscription: Map<String, dynamic>?
Required: No
Description: Parameter for adding a subscription for a selected channel.
The SDK provides the Subscription class with factory constructors for each subscription type:
class Subscription {
final String type;
final int resourceId;
final String? status;
final int? priority;
final String? email;
final String? phone;
final String? provider;
final String? subscriptionId;
final Map<String, dynamic>? customFields;
final List<dynamic>? cats;
final Map<String, dynamic>? ccData;
}
The subscription parameter is only used when working with JWT authorization.
Common subscription fields (for all implementations)
| Field | Type | Required | Description |
|---|---|---|---|
type | String | Yes | Channel type (discriminator). |
resourceId | int | Yes | Resource/source subscription ID. |
status | String? | No | Subscription status (e.g., active/suspended). |
priority | int? | No | Delivery priority. |
customFields | Map<String, dynamic>? | No | Custom subscription fields. |
cats | List<dynamic>? | No | Subscription categories. |
Subscription variants
Email subscription (type = "email")
| Field | Type | Required | Description |
|---|---|---|---|
resourceId | int | Yes | Altcraft resource ID |
email | String | Yes | Email address |
final emailSub = Subscription.email(
resourceId: 10,
email: 'user@example.com',
status: 'active',
priority: 1,
customFields: {'source': 'flutter_app'},
cats: ['promo', 'news'],
);
SMS subscription (type = "sms")
| Field | Type | Required | Description |
|---|---|---|---|
resourceId | int | Yes | Altcraft resource ID |
phone | String | Yes | Phone number in international format |
final smsSub = Subscription.sms(
resourceId: 10,
phone: '+79001234567',
status: 'active',
);
Push subscription (type = "push")
| Field | Type | Required | Description |
|---|---|---|---|
resourceId | int | Yes | Altcraft resource ID |
provider | String | Yes | Provider (e.g., "android-firebase") |
subscriptionId | String | Yes | Unique subscription ID at the provider |
final pushSub = Subscription.push(
resourceId: 10,
provider: 'android-firebase',
subscriptionId: 'provider-sub-id',
status: 'active',
priority: 1,
customFields: {'source': 'flutter_app'},
cats: ['promo', 'news'],
);
CcData subscription (type = "cc_data")
| Field | Type | Required | Description |
|---|---|---|---|
resourceId | int | Yes | Altcraft resource ID |
ccData | Map<String, dynamic> | Yes | Channel-specific data (chat ID, number, tokens) |
final ccSub = Subscription(
type: 'cc_data',
resourceId: 10,
ccData: {'channel': 'telegram_bot', 'chat_id': '123456'},
);
utm: Map<String, dynamic>?
Required: No
Description: UTM tags. The SDK provides the UTM class:
class UTM {
final String? source;
final String? medium;
final String? campaign;
final String? content;
final String? keyword;
final String? temp;
}
AltcraftSDK.mobileEvent(
sid: 'pixel-000000000000000000000000',
eventName: 'app_install',
utm: const {
'campaign': 'summer_campaign',
'content': 'main_banner',
'keyword': 'mobile_sdk',
'medium': 'push',
'source': 'flutter_app',
'temp': 'a1',
},
);
Usage examples
Simple event
AltcraftSDK.mobileEvent(
sid: 'pixel-000000000000000000000000',
eventName: 'app_open',
);
Passing data via payload
AltcraftSDK.mobileEvent(
sid: 'pixel-000000000000000000000000',
eventName: 'purchase',
payload: const {
'orderId': 'A-1001',
'amount': 3990,
'currency': 'RUB',
'items': [
{'sku': 'sku-1', 'qty': 2},
],
},
);
Passing matching / matchingType
AltcraftSDK.mobileEvent(
sid: 'pixel-000000000000000000000000',
eventName: 'profile_update',
payload: const {'source': 'settings'},
matching: const {'email': 'ivan.petrov@example.com'},
matchingType: 'email',
);
Passing subscription (JWT)
import 'package:altcraft_sdk/altcraft_sdk.dart';
final pushSub = Subscription.push(
resourceId: 10,
provider: 'android-firebase',
subscriptionId: 'provider-sub-id',
status: 'active',
priority: 1,
customFields: {'source': 'flutter_app'},
cats: ['promo', 'news'],
);
AltcraftSDK.mobileEvent(
sid: 'pixel-000000000000000000000000',
eventName: 'jwt_bind_subscription',
subscription: pushSub.toMap(),
);
When passing subscription through MethodChannel, some fields are serialized to string format (e.g., custom_fields and cats are passed as JSON strings). Pass JSON-compatible values.
Receiving SDK Events in the Application
In Flutter, SDK events are delivered to Dart via Stream<SdkEvent> (uses EventChannel under the hood).
class SdkEvent {
final String function;
final int? code;
final String message;
final String type;
final Map<String, dynamic>? value;
final String? timestamp;
}
Event types:
event— informational events and successful operations;error— execution errors;retryError— errors for operations where the SDK performs automatic retry.
The timestamp field contains the event timestamp in yyyy-MM-dd HH:mm:ss.SSS format (provided by the native SDK).
Subscribing to Events
Each call to subscribeToEvents() creates an independent Stream<SdkEvent>. To unsubscribe, save a reference to the StreamSubscription and call cancel().
import 'dart:async';
import 'package:altcraft_sdk/altcraft_sdk.dart';
StreamSubscription<SdkEvent>? sdkEventsSubscription;
void subscribeToSdkEvents() {
sdkEventsSubscription = AltcraftSDK.subscribeToEvents().listen(
(SdkEvent event) {
switch (event.type) {
case 'event':
print('SDK event: ${event.message}');
break;
case 'error':
print('SDK error: ${event.message}');
break;
case 'retryError':
print('SDK retry error: ${event.message}');
break;
default:
print('SDK unknown event type: ${event.type}');
}
},
);
}
Unsubscribing from Events
Future<void> unsubscribeFromSdkEvents() async {
await sdkEventsSubscription?.cancel();
sdkEventsSubscription = null;
await AltcraftSDK.unsubscribeFromEvents();
}
After calling unsubscribeFromEvents(), event delivery from the native SDK stops. To receive events again, call subscribeToEvents().
Handling SDK Errors
The SDK may throw AltcraftException on method call errors via MethodChannel:
class AltcraftException implements Exception {
final String code;
final String message;
final Object? details;
}
A special case is SdkNotInitializedException (code SDK_NOT_INITIALIZED), thrown when methods are called before SDK initialization:
import 'package:altcraft_sdk/altcraft_sdk.dart';
try {
await AltcraftSDK.getStatusOfLatestSubscription();
} on SdkNotInitializedException {
print('SDK not initialized yet');
} on AltcraftException catch (e) {
print('SDK error (${e.code}): ${e.message}');
}
List of All SDK Events
Event list
| Code | Description |
|---|---|
| 200 | SDK configuration is installed |
| 201 | push provider set |
| 202 | received a notification unrelated to the Altcraft Platform |
| 203 | received Altcraft push notification |
| 204 | push is posted |
| 205 | SDK data has been cleared |
| 206 | waiting for SDK initialization to complete |
| 207 | waiting for push token update to complete |
| 220 | receiver override event |
| 230 | subscribe request succeeded |
| 231 | push suspend request succeeded |
| 232 | push unsubscribed request succeeded |
| 233 | push update request succeeded |
| 234 | push unsuspend request succeeded |
| 235 | profile status request succeeded |
| 236 | push event delivered successfully |
| 237 | mobile event delivered successfully |
| 401 | the configuration is not set |
| 402 | userTag is null. It is impossible to identify the user |
| 404 | SDK initialization timeout has expired |
| 405 | mobile event parts is null |
| 422 | unsuspend request data is null |
| 423 | profile request data is null |
| 430 | subscribe request failed |
| 431 | suspend request failed |
| 432 | unsubscribed request failed |
| 433 | update request failed |
| 434 | unsuspend request failed |
| 435 | status request failed |
| 436 | push event delivery failed |
| 437 | mobile event request failed |
| 450 | push data is null |
| 451 | uid in the push data is null or empty, it is impossible to send a push event to the server |
| 452 | error uploading the notification image |
| 453 | couldn't create notification |
| 454 | foreground info is null |
| 455 | the notification channel has not been created |
| 471 | invalid provider. Available - android-firebase, android-huawei, android-rustore |
| 472 | invalid customFields: not all values are primitives |
| 480 | subscribe retry limit reached (request removed from DB) |
| 484 | push event retry limit reached (request removed from DB) |
| 485 | mobile event retry limit reached (request removed from DB) |
| 501 | config data is null |
| 502 | current push token is null |
| 503 | userTag is null. It is impossible to identify the user |
| 504 | no permission to send notifications |
| 505 | no internet connection, retry when connection is restored |
| 506 | failed to update the push token. The subscription request was rejected |
| 520 | push subscribe request data is null |
| 521 | token update request data is null |
| 524 | push event request data is null |
| 525 | mobile event request data is null |
| 529 | common data is null |
| 530 | subscribe request failed (retryable) |
| 531 | token update request failed (retryable) |
| 534 | push event delivery failed (retryable) |
| 535 | mobile event delivery failed (retryable) |
| 540 | JWT token is null |
| 541 | matching mode is null |
| 542 | JWT payload exceeds allowed size (16 KB limit): input rejected to prevent DoS |
| 543 | JWT does not contain a payload |
| 544 | auth data is null |
| 545 | matching claim does not contain a matching ID |
| 560 | response data is null |
ActionFieldBuilder
The SDK provides ActionFieldBuilder for structured profile field management. The builder produces a map compatible with the native SDK, which should be merged with profileFields before passing to pushSubscribe, updateProfileFields, or similar APIs.
class ActionFieldBuilder {
final String key;
Map<String, dynamic> set(dynamic value);
Map<String, dynamic> unset(dynamic value);
Map<String, dynamic> incr(dynamic value);
Map<String, dynamic> add(dynamic value);
Map<String, dynamic> delete(dynamic value);
Map<String, dynamic> upsert(dynamic value);
}
ActionFieldBuilder actionField(String key);
Available actions:
| Method | Description |
|---|---|
set(value) | Set the field to the given value. |
unset(value) | Remove the field value. |
incr(value) | Increment a numeric field by the given value. |
add(value) | Add a value to a set/array field. |
delete(value) | Remove a value from a set/array field. |
upsert(value) | Set if the field is missing; update if it exists. |
Usage example:
import 'package:altcraft_sdk/altcraft_sdk.dart';
final profileFields = <String, dynamic>{
...actionField('_fname').set('Ivan'),
...actionField('_lname').set('Petrov'),
...actionField('login_count').incr(1),
...actionField('visited_pages').add('/settings'),
...actionField('old_field').unset(null),
};
AltcraftSDK.updateProfileFields(
profileFields: profileFields,
skipTriggers: false,
);
Additional SDK Functions
Clearing SDK Data
await AltcraftSDK.clear();
This function clears SDK data and cancels all background tasks awaiting execution.
Manual Push Event Registration
These functions are only used if you implement your own notification handling logic and do not pass them to the SDK automatically.
Android
In Flutter, manual push event registration functions are available on Android:
deliveryEvent(message, messageUID)— register notification delivery;openEvent(message, messageUID)— register notification opening.
Parameters:
message: Map<String, String>?— notification data payload as a string dictionary.messageUID: String?— message identifier.
AltcraftSDK.deliveryEvent(
const {
'_uid': 'push-message-uid-0001',
'_provider': 'android-firebase',
},
'push-message-uid-0001',
);
AltcraftSDK.openEvent(
const {
'_uid': 'push-message-uid-0001',
'_provider': 'android-firebase',
},
'push-message-uid-0001',
);
Passing rules:
- you can pass only
message(SDK will extract the message ID from the payload if present); - you can pass only
messageUID(if the payload is unavailable but the ID is known); - if both parameters are
null— the event will not be registered correctly (no data to identify the message).
iOS
Manual push event registration via Flutter is not implemented on iOS. If manual event registration is required, perform it in the native part of the application.
See the iOS instructions.
Updating Profile Fields
AltcraftSDK.updateProfileFields({
Map<String, dynamic>? profileFields,
bool? skipTriggers,
});
This function updates profile fields on the server.
profileFields— map of profile fields to update.skipTriggers— when this flag is activated, the profile will be ignored in mailing and scenario triggers.
AltcraftSDK.updateProfileFields(
profileFields: const {
'_fname': 'Ivan',
'_lname': 'Petrov',
},
skipTriggers: false,
);
Forced Token Update
await AltcraftSDK.forcedTokenUpdate();
This function initiates a forced push token update.
Deleting Device Token
await AltcraftSDK.deleteDeviceToken('android-firebase');
This function deletes the device token for the specified provider.
Changing Push Provider Priority
await AltcraftSDK.changePushProviderPriorityList(
const ['android-firebase', 'android-huawei', 'android-rustore'],
);
This function changes the push provider priority list.
Checking Altcraft Push
final bool isAltcraft = await AltcraftSDK.isAltcraftPush(
const {
'_ac_push': 'Altcraft',
'_uid': 'push-message-uid-0001',
},
);
This function checks whether a push message belongs to Altcraft. Returns true if the message belongs to Altcraft, and false otherwise.
Unlocking Initial Operations in Session
AltcraftSDK.unlockInitialOperationsInThisSession();