updateUserAttributes method

Future<UserAttributesUpdateResult> updateUserAttributes({
  1. required String userToken,
  2. bool? isPaying,
  3. String? plan,
  4. double? mrr,
  5. String? currency,
  6. String? signingSecret,
  7. String? signature,
  8. int? timestamp,
})

Reports self-declared user attributes.

Calls that report payment attributes (isPaying, plan, or mrr) must carry an HMAC-SHA256 signature produced with the app's SDK signing secret (cpt-user-attrs-v1).

If signature is provided, it and timestamp are sent directly. Otherwise, if a signing secret is configured in signingSecret or FeedbackClientConfig.sdkSigningSecret, the SDK automatically signs the payload. Requests without payment attributes (identity or currency only) remain unsigned.

Implementation

Future<UserAttributesUpdateResult> updateUserAttributes({
  required String userToken,
  bool? isPaying,
  String? plan,
  double? mrr,
  String? currency,
  String? signingSecret,
  String? signature,
  int? timestamp,
}) async {
  final body = <String, dynamic>{
    'userToken': userToken,
  };
  if (isPaying != null) body['isPaying'] = isPaying;
  if (plan != null && plan.isNotEmpty) body['plan'] = plan.trim();
  if (mrr != null) body['mrr'] = mrr;
  if (currency != null && currency.isNotEmpty) body['currency'] = currency.trim();

  final assertsPayment =
      body.containsKey('isPaying') || body.containsKey('plan') || body.containsKey('mrr');

  if (signature != null && signature.isNotEmpty) {
    body['signature'] = signature;
    body['timestamp'] =
        timestamp ?? (DateTime.now().toUtc().millisecondsSinceEpoch ~/ 1000);
  } else if (assertsPayment) {
    final secret = signingSecret ?? config.sdkSigningSecret;
    if (secret != null && secret.isNotEmpty) {
      final ts =
          timestamp ?? (DateTime.now().toUtc().millisecondsSinceEpoch ~/ 1000);
      final sig = SdkAttributeSigner.sign(
        secret: secret,
        appKey: config.appKey,
        userToken: userToken,
        raw: body,
        timestamp: ts,
      );
      body['timestamp'] = ts;
      body['signature'] = sig;
    }
  }

  final json = await _sendJson(
    method: 'PUT',
    path: '/api/v1/public/apps/${config.appKey}/user',
    body: body,
    userToken: userToken,
    acceptedStatuses: const [200],
  );
  return UserAttributesUpdateResult.fromJson(json);
}