@@ -44,7 +44,7 @@ internal static class ProgressionStatusExtensions
4444 /// Player progressing through a world / level / stage. Track via
4545 /// <see cref="ImmutableAudience.Track(IEvent)"/>.
4646 /// </summary>
47- public class Progression : IEvent
47+ public class Progression : IBuiltInEvent
4848 {
4949 /// <summary>
5050 /// Required. Where the player is in the progression flow.
@@ -134,7 +134,7 @@ internal static class ResourceFlowExtensions
134134 /// In-game currency earned or spent. Track via
135135 /// <see cref="ImmutableAudience.Track(IEvent)"/>.
136136 /// </summary>
137- public class Resource : IEvent
137+ public class Resource : IBuiltInEvent
138138 {
139139 /// <summary>
140140 /// Required. Whether this is a gain or a spend.
@@ -193,7 +193,7 @@ public Dictionary<string, object> ToProperties()
193193 /// Real-money transaction. Track via
194194 /// <see cref="ImmutableAudience.Track(IEvent)"/>.
195195 /// </summary>
196- public class Purchase : IEvent
196+ public class Purchase : IBuiltInEvent
197197 {
198198 /// <summary>
199199 /// Required. ISO 4217 three-letter uppercase currency code (for
@@ -202,9 +202,11 @@ public class Purchase : IEvent
202202 public string ? Currency { get ; set ; }
203203
204204 /// <summary>
205- /// Required. The transaction amount in <see cref="Currency"/>.
205+ /// Required. The transaction amount in <see cref="Currency"/>, as a
206+ /// numeric-looking string (e.g. <c>"9.99"</c>), not a number, to
207+ /// avoid floating-point precision loss.
206208 /// </summary>
207- public decimal ? Value { get ; set ; }
209+ public string ? Value { get ; set ; }
208210
209211 /// <summary>
210212 /// Optional. Stable identifier of the item purchased.
@@ -247,13 +249,13 @@ public Dictionary<string, object> ToProperties()
247249 if ( Currency == null || ! IsIso4217 ( Currency ) )
248250 throw new ArgumentException (
249251 $ "Purchase.Currency '{ Currency } ' must be a three-letter uppercase ISO 4217 code") ;
250- if ( Value is null )
252+ if ( string . IsNullOrEmpty ( Value ) )
251253 throw new ArgumentException ( "Purchase.Value is required. Set it before calling Track(IEvent)." ) ;
252254
253255 var props = new Dictionary < string , object >
254256 {
255257 [ "currency" ] = Currency ,
256- [ "value" ] = Value . Value
258+ [ "value" ] = Value
257259 } ;
258260
259261 if ( ItemId != null ) props [ "item_id" ] = ItemId ;
@@ -316,7 +318,7 @@ internal static class AchievementTypeExtensions
316318 /// Player unlocked an achievement. Track via
317319 /// <see cref="ImmutableAudience.Track(IEvent)"/>.
318320 /// </summary>
319- public class AchievementUnlocked : IEvent
321+ public class AchievementUnlocked : IBuiltInEvent
320322 {
321323 /// <summary>
322324 /// Required. Stable identifier for the achievement (for example,
@@ -362,7 +364,7 @@ public Dictionary<string, object> ToProperties()
362364 /// Named milestone or achievement reached by the player. Track via
363365 /// <see cref="ImmutableAudience.Track(IEvent)"/>.
364366 /// </summary>
365- public class MilestoneReached : IEvent
367+ public class MilestoneReached : IBuiltInEvent
366368 {
367369 /// <summary>
368370 /// Required. The milestone identifier (for example,
0 commit comments