Purchase Status Updates

This event is triggered whenever a change happens to a purchase throughout its lifecycle.

The purchase.updated data structure provides you all the relevant information known about the purchase at the time the event is sent. It is delivered to you via your webhook.

📘

Interested in a Direct Connection to your Data Warehouse?

Contact [email protected] if you're interested in receiving this data in bulk or integrated directly into your data warehouse.

Delivery Timing

Events are sent in a near real-time. You will receive a purchase.updated event on a 2 minute delay after the update occurred. If an update occurs to a purchase within the 2 minutes, the timer is reset until there are no changes detected from the Nami SDK or the Platform Provider before sending on to you.

This mechanism ensures the data is provided in a timely fashion, while also cutting down on the number of events sent for one purchase.

Multiple updates for a purchase are possible. The collapse_key is the primary key for a specific purchase. Store the most recent version of each purchase update for a given collapse_key to have a complete view of all purchases Nami knows about.

Event Data Structure

Top-Level Elements

Field NameTypeDefinition
billing_cyclesInteger or NullThe number of total billing cycles that have occurred for this purchase. The original purchase counts as first cycle.
canceled_atTimestamp or NullWhen the subscription was cancelled.
current_term_lengthString (ISO-8601 Time Interval Format)
or Null
The current term length of the subscriptions. Requires Platform Product Sync to be enabled. Contact support for details.
devices_with_accessList of of DevicesWithAccessA list of devices that have access to the purchase. Ordered by device claim date, oldest to newest.
entitlementsList of PurchaseEntitlementsA list of entitlements the purchase grants.
expires_atTimestamp or NullThe current time when the subscription will expire.
is_activeBoolean or NullWhether the purchase is currently active.
is_auto_renewableBoolean or NullWhether the purchase is auto-renewing.
is_free_trial_conversionBoolean or NullWhether the purchase converted from a free trial. Note: If Nami did not observe the original purchase, we do not know if the purchase was a free trial. In this case, this field will be null.
is_in_trial_periodBoolean or NullWhether the purchase is currently in a trial period. Note: We only know if the purchase is in a free trial, if we observed the original purchase.
is_productionBooleanWhether the purchase occurred in production or not.
is_in_intro_offer_periodBoolean or NullWhether the purchase is in an introductory offer period.
last_seen_device_idUUID or NullThe identifier for the last seen device with access to this purchase.
last_seen_external_idString or NullThe external identifier associated with this purchase.
not_beforeTimestamp or NullWhen this purchase became active.
original_purchase_guidString or NullA reference to a previous purchase in the case of a plan change.
payment_issues_began_atTimestamp or NullWhen payment issues started.
platform_typeStringThe platform type (e.g. apple, google)
price_in_usdDecimal or NullThe estimated pricing in USD using currency exchange rates from the day of the purchase.
product_ref_idStringThe identifier for this purchase as configured with the app store platform.
purchase_countryString (2 Character Enum) or NullThe country code for the purchase from the app store platform.
purchase_currencyString (3 Character Enum) or NullThe currency code for the purchase from the app store platform.
purchase_guidStringThe identifier provided for the purchase from the app store platform.
purchase_priceDecimal or NullThe local price for the purchase from the app store platform.
revoked_atTimestamp or NullWhen the purchase was revoked.
transaction_idStringThe transaction identifier for the purchase from the app store platform.

DevicesWithAccess Elements

A list of devices that have access to the purchase.

Field NameTypeDefinition
claim_typeStringHow a device gained access to purchase (original_purchaser, family_sharing, cross_platform_shared, etc).
first_launchTimestampThe time the device first registered with Nami
idUUIDThe device install's unique identifier.
last_activeTimestampThe end time of the last known app session.
platform_typeStringWhat app platform of the device (apple, google)

PurchaseEntitlement Elements

A list of entitlements the purchase grants.

Field NameTypeDescription
descriptionStringEntitlement description in Nami Control Center.
entitlement_ref_idStringEntitlement reference in Nami Control Center.
idUUIDNami internal identifier for an entitlement.
nameStringEntitlement display name in Nami Control Center.
typeStringbinary_auth is an entitlement to gate features with an ‘on/off’ switch.

EventAttributes Elements

Metadata which can be useful when processing this event.

Field NameTypeDefinition
app_idUUID or NullNami App ID (if applicable) for the event.
collapse_keyStringCollapse Key is the primary key for versioned events.
event_idUUIDUnique ID for a specific event.
event_timeTimestampUTC Timestamp of Event in ISO-8601 format.
event_typeStringThe type of event.
org_idUUID or NullYour Nami Org ID.
platform_idUUID or NullApp Platform ID (if applicable) for the event.
subscription_idUUID or NullSubscription that caused the event delivery.
versionStringVersion of event format

Example Payload

{
    "attributes": {
      "app_id": "486c1c9f-37b1-4873-9ff6-e78e563d184a",
      "collapse_key": "6b275a67-0bbb-4f3a-99b9-6600bf711993",
      "event_id": "b4ad74e4-8986-461b-aa08-473a19c608b2",
      "event_time": "2022-09-20T20:12:35.818538Z",
      "event_type": "purchase.updated",
      "org_id": "a8d39aa3-e393-46ee-8cb4-e8b8c0bd50e7",
      "platform_id": "aaf69dba-ef67-40f5-82ec-c7623a2848a6",
      "subscription_id": "7e0977f8-27c9-49c5-8356-e82cbf34b161",
      "version": "2.0"
    },
    "data": {
      "billing_cycles": 5,
      "canceled_at": null,
      "current_term_length": null,
      "devices_with_access": [
        {
          "claim_type": "original_purchaser",
          "first_launch": "2022-09-19T23:15:25.201213Z",
          "id": "eadea2bf-79b3-444c-b3a4-9e0127abc840",
          "last_active": "2022-09-20T19:37:38.713391Z",
          "platform_type": "google"
        }
      ],
      "entitlements": [
        {
          "description": null,
          "entitlement_ref_id": "premium",
          "id": "71a267cd-de70-4ba9-b743-24ef2b4be3ae",
          "name": "Premium",
          "type": "binary_auth"
        },
        {
          "description": null,
          "entitlement_ref_id": "gold",
          "id": "c1ec3e32-25b5-4eb9-b1e1-6fd429581b4a",
          "name": "Gold",
          "type": "binary_auth"
        }
      ],
      "expires_at": "2022-09-20T20:19:31.302000Z",
      "is_active": true,
      "is_auto_renewable": true,
      "is_free_trial_conversion": false,
      "is_in_intro_offer_period": false,
      "is_in_trial_period": false,
      "is_production": false,
      "last_seen_device_id": "eadea2bf-79b3-444c-b3a4-9e0127abc840",
      "last_seen_external_id": null,
      "not_before": "2022-09-20T19:37:30.193000Z",
      "original_purchase_guid": null,
      "payment_issues_began_at": null,
      "platform_type": "google",
      "price_in_usd": "4.99",
      "product_ref_id": "your_product_name",
      "purchase_country": "US",
      "purchase_currency": "USD",
      "purchase_guid": "google_play_token_or_apple_original_transacation_id",
      "purchase_price": "4.9900",
      "revoked_at": null,
      "transaction_id": "GPA.1234-5678-9012-12345..3"
    }
  }

Switching from RevenueCat?

For customers switching from RevenueCat, this event provides substantially similar information as the ETL Exports. Here's what you need to know about the differences between RevenueCat ETL Exports and Nami Purchase Updated events:

Data structure differences

RevenueCat FieldNami FieldNotes
renewal_numberbilling_cyclesNami counts the original purchase as first cycle
unsubscribe_detected_atcanceled_at
entitlement_identifiersentitlementsEntitlements are provided as objects instead of a list of strings.
end_timeexpires_at
n/ais_active
is_trial_conversionis_free_trial_conversionIf we did not observe the original purchase, we may not know if the purchase was a free trial conversion. In this case, we will provide a null value for this field.
is_trial_periodis_in_trial_periodIf we did not observe the original purchase, we may not know if the purchase is in a free trial. In this case, we will provide a null value for this field.
is_sandboxis_production
rc_last_seen_app_user_id_aliaslast_seen_device_idRevenueCat doesn’t distinguish an external ID from an anonymous device ID.
rc_last_seen_app_user_id_aliaslast_seen_external_idRevenueCat seems to provide either the external ID or the anonymous ID but not both.
start_timenot_before
n/aoriginal_purchase_guidA reference to the original store purchase identifier, which may be available in the case of cross grades, downgrades, or upgrades.
billing_issues_detected_atpayment_issues_began_at
storeplatform_type
product_identifierproduct_ref_id
countrypurchase_country
purchased_currencypurchase_currency
original_store_transaction_idpurchase_guid
price_in_purchased_currencypurchase_price
refunded_atrevoked_atMore precise definition as we know if a subscription is revoked, but we do not always know if that involved a refund.
store_transaction_idtransaction_id