Skip to main content
Altcraft Docs LogoAltcraft Docs Logo
User guide iconUser guide
Developer guide iconDeveloper guide
Admin guide iconAdmin guide
English
  • Русский
  • English
Login
    User API documentationAPI interactionMatching
      Profilesarrow
    • Import profileUpdate profileImport multiple profilesUpdate multiple profilesAdd multiple profilesAdd profile to databaseImport profile to RabbitMQGet profile dataUploading profiles to a fileDelete profileSubscription fields functional updateDatabase fields functional updateMerging multiple profilesUnsubscribe profile from resourceProfile splitting
        Subscriptionsarrow
      • Add or edit subscriptionGet all profile subscriptionsGet all subscriptions from multiple profilesGet profile subscriptionDelete profile subscriptionRestore deleted subscriptionSuspend all subscriptionsUnsuspend all suspended subscriptions
        Action historyarrow
      • Get profile action historyGet multiple profiles action history
        Profile relationsarrow
      • Attach relationDetach relationModify relation propertiesOverwrite relation propertiesGet profile relations infoGet profile relations info
      Get data for multiple profiles
      Databasesarrow
    • Get database statisticsUpdate statistics on databaseGet database listGet database informationGet database fieldsDatabase wipe
      Resourcesarrow
    • Get resource statisticsUpdate statistics on resourceGet resources listGet resource informationGet resource subscription fields
      Segmentsarrow
    • Create segmentGet statistics on resourceUpdate statistics on segmentAdd or remove profileGet profile data in a static segmentUpdate segmentGet segment informationGet segments listDelete segment
      Suppression listsarrow
    • Create suppression listUpdate suppression listGet suppression list infoGet the list of suppression listsDelete suppression listUpload suppression list data to file
        Suppression list actionsarrow
      • Check if email is suppressedAdd email to suppression listAdd multiple emails to suppression listRemove email from suppression listRemove all emails from suppression listCheck if domain is suppressedAdd domain to suppression listAdd multiple domains to suppression listRemove domain from suppression listRemove all domains from suppression listCheck if phone number is suppressedAdd phone number to suppression listAdd multiple phones to suppression listRemove phone number from suppression listRemove all phone numbers from suppression list
      Templates and fragmentsarrow
    • Get templates listGet template infoDelete templateAdd templateUpdate templateChannel object
      Campaignsarrow
    • Get campaign informationGet campaign listActivate campaignComplete campaignDeactivate campaignGet campaign status
      Mailingsarrow
    • Activate mailingDeactivate mailingGet mailing listGet mailing informationGet mailing logClone mailingDelete mailingGet mailing status
        Broadcast mailingsarrow
      • Get broadcasts listGet broadcast informationCreate broadcast mailingUpdate broadcast mailingLaunch a broadcast mailing
        Regular mailingsarrow
      • Get regular mailings listGet regular mailing informationCreate regular mailingUpdate regular mailingLaunch a regular mailing
        Trigger mailingsarrow
      • Get trigger mailings listGet trigger mailing informationCreate trigger mailingUpdate trigger mailingTrigger launch (API call)Profile import + trigger mailing launchTask for bulk trigger launchTask for bulk profiles import + trigger launchBulk trigger launchBulk profiles import + trigger mailing launchClone a trigger mailingData array
      Automation scenariosarrow
    • Engage profile in scenarioImport and engage profile in scenarioBatch import and engage profiles in a scenarioTask for batch import and engaging profiles in the scenarioGet scenarios listActivate scenarioDeactivate scenario
      Loyalty Programsarrow
    • Get profile tier in a loyalty programExport points transactionsExpiring points for a periodGet profile account transactionsGet trigger promotions listAccrue points to a memberRedeem member pointsCommit temporary transactionPreliminary Order CalculationOrder ConfirmationRoll back temporary transactionCancel points transactionGet points account balanceRegister member in a loyalty programBatch adding participants to loyalty programTask for batch add participants to loyalty programRemove member from loyalty program
      Formsarrow
    • Get form informationGet form listExport form fill data by userExport form fill dataPublish formUnpublish formDelete form
      Promo codesarrow
    • Import promo codesGet promo code informationActivate promo codeUpdate promo codeAttach promo codeDetach promo codeGet all promo codes
      Goalsarrow
    • Goals and goal values registration
      Application push notificationsarrow
    • Processing and adding a subscriptionAdd app push events
      Marketarrow
      • Market objectsarrow
      • Order data objectProduct data objectSKU data objectCategories arrayCustom fields array
        Ordersarrow
      • Import order and item statusesGet orders listDelete orderGet order statusUpdate order line status
        Products and SKUarrow
      • Import products, SKUs and categoriesImport SKUs and categoriesGet products listGet SKUs listDelete productsDelete SKU
      Analytic reportsarrow
    • Get summary reportGet soft bounces reportGet undeliveries report
      Sendersarrow
    • Get senders list
        Virtual senders (Smart accounts only)arrow
      • Get virtual senders listGet virtual sender informationClone virtual senderCreate virtual senderUpdate virtual senderDelete virtual sender
      External datatables queriesarrow
      • Segmentation queriesarrow
      • Add segmentation queryUpdate segmentation queryGet segmentation query informationGet segmentation queries listDelete segmentation query
        Template queriesarrow
      • Add template queryUpdate template queryGet template query informationGet template queries listDelete template query
      Objectsarrow
    • AKMTA objectContent objectEmail rule objectFile objectProfile data objectSMS rule objectSender objectSender typesStart schedule objectSubscription objectTrigger types
      Miscellaneousarrow
    • Upload fileGet message web versionPush providersDeduplication of requestsHow to send API request with RabbitMQList of gender identificationsObtain valid values for fields: browsers, devices, tz, oses, languages
    Importing the API collection in PostmanList of API endpoints
      SDKarrow
      • mSDKarrow
        • Androidarrow
        • Quick StartSDK FunctionalitySDK ConfigurationPublic SDK API
            Provider configuration androidarrow
          • Firebase Cloud MessagingHuawei Mobile ServicesRuStore
          iOSarrow
        • Quick StartSDK FunctionalitySDK ConfigurationPublic SDK API
            Provider configurationarrow
          • Apple Push Notification ServiceFirebase Cloud MessagingHuawei Mobile Services
          React Native (Android/iOS)arrow
        • Quick StartSDK ConfigurationSDK FunctionalityPublic SDK APIProvider setup
          Flutter (Android/iOS)arrow
        • Quick StartSDK ConfigurationSDK FunctionalitySDK Public APIProvider Setup
        Managing JWT and Role Token
      Web Push SDK
  • SDK
  • mSDK
  • Flutter (Android/iOS)
  • SDK Functionality

SDK Functionality

tip

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 creating LogIn and LogOut transitions.

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, only profile = null will 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 — always null for 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;
  • error and errorText, 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):

  • String
  • bool
  • num (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',
},
);
Note

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,
);
Note

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 subscribed to suspended;
  • changes the status in subscriptions of the profile pointed to by the current JWT from suspended to subscribed (if the profile pointed to by the JWT exists and contains subscriptions);
  • returns ResponseWithHttpCode?, where response?.profile is the current profile pointed to by the JWT (returns null if 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 execute pushSubscribe() 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 to subscribed;
  • 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. If null is 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​


tip

On the native side of the application, you can use the functions described in the articles for the corresponding platforms: Android and iOS.

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, context is 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
Important

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 is
  • int / double / bool — converted to string representation
  • Map / List — serialized to a JSON string
  • null — key is not passed (field is removed from payload)
Note

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.

Note

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;
}
Note

The subscription parameter is only used when working with JWT authorization.

Common subscription fields (for all implementations)

FieldTypeRequiredDescription
typeStringYesChannel type (discriminator).
resourceIdintYesResource/source subscription ID.
statusString?NoSubscription status (e.g., active/suspended).
priorityint?NoDelivery priority.
customFieldsMap<String, dynamic>?NoCustom subscription fields.
catsList<dynamic>?NoSubscription categories.

Subscription variants

Email subscription (type = "email")

FieldTypeRequiredDescription
resourceIdintYesAltcraft resource ID
emailStringYesEmail 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")

FieldTypeRequiredDescription
resourceIdintYesAltcraft resource ID
phoneStringYesPhone number in international format
final smsSub = Subscription.sms(
resourceId: 10,
phone: '+79001234567',
status: 'active',
);

Push subscription (type = "push")

FieldTypeRequiredDescription
resourceIdintYesAltcraft resource ID
providerStringYesProvider (e.g., "android-firebase")
subscriptionIdStringYesUnique 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")

FieldTypeRequiredDescription
resourceIdintYesAltcraft resource ID
ccDataMap<String, dynamic>YesChannel-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(),
);
Note

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
CodeDescription
200SDK configuration is installed
201push provider set
202received a notification unrelated to the Altcraft Platform
203received Altcraft push notification
204push is posted
205SDK data has been cleared
206waiting for SDK initialization to complete
207waiting for push token update to complete
220receiver override event
230subscribe request succeeded
231push suspend request succeeded
232push unsubscribed request succeeded
233push update request succeeded
234push unsuspend request succeeded
235profile status request succeeded
236push event delivered successfully
237mobile event delivered successfully
401the configuration is not set
402userTag is null. It is impossible to identify the user
404SDK initialization timeout has expired
405mobile event parts is null
422unsuspend request data is null
423profile request data is null
430subscribe request failed
431suspend request failed
432unsubscribed request failed
433update request failed
434unsuspend request failed
435status request failed
436push event delivery failed
437mobile event request failed
450push data is null
451uid in the push data is null or empty, it is impossible to send a push event to the server
452error uploading the notification image
453couldn't create notification
454foreground info is null
455the notification channel has not been created
471invalid provider. Available - android-firebase, android-huawei, android-rustore
472invalid customFields: not all values are primitives
480subscribe retry limit reached (request removed from DB)
484push event retry limit reached (request removed from DB)
485mobile event retry limit reached (request removed from DB)
501config data is null
502current push token is null
503userTag is null. It is impossible to identify the user
504no permission to send notifications
505no internet connection, retry when connection is restored
506failed to update the push token. The subscription request was rejected
520push subscribe request data is null
521token update request data is null
524push event request data is null
525mobile event request data is null
529common data is null
530subscribe request failed (retryable)
531token update request failed (retryable)
534push event delivery failed (retryable)
535mobile event delivery failed (retryable)
540JWT token is null
541matching mode is null
542JWT payload exceeds allowed size (16 KB limit): input rejected to prevent DoS
543JWT does not contain a payload
544auth data is null
545matching claim does not contain a matching ID
560response 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:

MethodDescription
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​

Note

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();
Last updated on Jul 6, 2026
Previous
SDK Configuration
Next
SDK Public API
  • Working with Subscription Statuses
    • Changing Subscription Status
    • Requesting Subscription Status
  • Managing Provider Push Tokens
  • Push Notification Registration and Transmission to SDK
    • In native code
    • In Flutter code on Android
  • Mobile Events
  • Receiving SDK Events in the Application
    • Subscribing to Events
    • Unsubscribing from Events
    • Handling SDK Errors
    • List of All SDK Events
  • ActionFieldBuilder
  • Additional SDK Functions
    • Clearing SDK Data
    • Manual Push Event Registration
      • Android
      • iOS
    • Updating Profile Fields
    • Forced Token Update
    • Deleting Device Token
    • Changing Push Provider Priority
    • Checking Altcraft Push
    • Unlocking Initial Operations in Session
© 2015 - 2026 Altcraft, LLC. All rights reserved.