updateUserAttributes method
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);
}