Skip to main content

Webhook event types and fields

Adapty sends webhooks in response to subscription events. This section defines these event types and the data contained in each webhook.

Webhook event types

You can send all event types to your webhook or choose only some of them. You can consult our Event flows to learn what kind of incoming data to expect and how to build your business logic around it. You can disable the event types you do not need when you set up your Webhook integration. There, you can also replace Adapty default event IDs with your own if required.

Event nameDescription
subscription_startedTriggered when a user activates a paid subscription without a trial period, meaning they are billed instantly.
subscription_renewedOccurs when a subscription is renewed and the user is charged. This event starts from the second billing, whether it's a trial or non-trial subscription.
subscription_renewal_cancelledA user has turned off subscription auto-renewal. The user retains access to premium features until the end of the paid subscription period.
subscription_renewal_reactivatedTriggered when a user reactivates subscription auto-renewal.
subscription_expiredTriggered when a subscription fully ends after being canceled. For instance, if a user cancels a subscription on December 12th but it remains active until December 31st, the event is recorded on December 31st when the subscription expires.
subscription_pausedOccurs when a user activates subscription pause (Android only).
subscription_deferredTriggered when a subscription purchase is deferred, allowing users to delay payment while maintaining access to premium features. This feature is available through the Google Play Developer API and can be used for free trials or to accommodate users facing financial challenges.
non_subscription_purchaseAny non-subscription purchase, such as lifetime access or consumable products like in-game coins.
trial_startedTriggered when a user activates a trial subscription.
trial_convertedOccurs when a trial ends and the user is billed (first purchase). For example, if a user has a trial until January 14th but is billed on January 7th, this event is recorded on January 7th.
trial_renewal_cancelledA user turned off subscription auto-renewal during the trial period. The user retains access to premium features until the trial ends but will not be billed or start a subscription.
trial_renewal_reactivatedOccurs when a user reactivates subscription auto-renewal during the trial period.
trial_expiredTriggered when a trial ends without converting to a subscription.
entered_grace_periodOccurs when a payment attempt fails, and the user enters a grace period (if enabled). The user retains premium access during this time.
billing_issue_detectedTriggered when a billing issue occurs during a charge attempt (e.g., insufficient card balance).
subscription_refundedTriggered when a subscription is refunded (e.g., by Apple Support).
non_subscription_purchase_refundedTriggered when a non-subscription purchase is refunded.
access_level_updatedOccurs when a user's access level is updated.

Webhook event structure

Adapty will send you only those events you've chosen in the Events names section of the Integrations -> Webhooks page.

Webhook events are serialized in JSON. The body of a POST request to your server will contain the serialized event wrapped into the structure below. All events follow the same structure, but their fields vary based on the event type, store, and your specific configuration. User attributes are the custom user attributes you set up, so they contain what you've configured. Attribution data fields are the same for all event types as well, however, the list of attributions will depend on which attribution sources you use in your mobile app. See below an example of an event:

Json
{
"profile_id": "00000000-0000-0000-0000-000000000000",
"customer_user_id": "UserIdInYourSystem",
"idfv": "00000000-0000-0000-0000-000000000000",
"idfa": "00000000-0000-0000-0000-000000000000",
"advertising_id": "00000000-0000-0000-0000-000000000000",
"profile_install_datetime": "2000-01-31T00:00:00.000000+0000",
"user_agent": "ExampleUserAgent/1.0 (Device; OS Version) Browser/Engine",
"email": "[email protected]",
"event_type": "subscription_started",
"event_datetime": "2000-01-31T00:00:00.000000+0000",
"event_properties": {
"store": "play_store",
"currency": "USD",
"price_usd": 4.99,
"profile_id": "00000000-0000-0000-0000-000000000000",
"cohort_name": "All Users",
"environment": "Production",
"price_local": 4.99,
"base_plan_id": "b1",
"developer_id": "onboarding_placement",
"ab_test_name": "onboarding_ab_test",
"ab_test_revision": 1,
"paywall_name": "UsedPaywall",
"proceeds_usd": 4.2315,
"variation_id": "00000000-0000-0000-0000-000000000000",
"purchase_date": "2024-11-15T10:45:36.181000+0000",
"store_country": "AR",
"event_datetime": "2000-01-31T00:00:00.000000+0000",
"proceeds_local": 4.2415,
"tax_amount_usd": 0,
"transaction_id": "0000000000000000",
"net_revenue_usd": 4.2415,
"profile_country": "AR",
"paywall_revision": "1",
"profile_event_id": "00000000-0000-0000-0000-000000000000",
"tax_amount_local": 0,
"net_revenue_local": 4.2415,
"vendor_product_id": "onemonth_no_trial",
"profile_ip_address": "10.10.1.1",
"consecutive_payments": 1,
"rate_after_first_year": false,
"original_purchase_date": "2000-01-31T00:00:00.000000+0000",
"original_transaction_id": "0000000000000000",
"subscription_expires_at": "2000-01-31T00:00:00.000000+0000",
"profile_has_access_level": true,
"profile_total_revenue_usd": 4.99,
"promotional_offer_id": null,
"store_offer_category": null,
"store_offer_discount_type": null
},
"event_api_version": 1,
"profiles_sharing_access_level": [{"profile_id": "00000000-0000-0000-0000-000000000000", "customer_user_id": "UserIdInYourSystem"}],
"attributions": {
"appsflyer": {
"ad_set": "Keywords 1.12",
"status": "non_organic",
"channel": "Google Ads",
"ad_group": null,
"campaign": "Social media influencers - Rest of the world",
"creative": null,
"created_at": "2000-01-31T00:00:00.000000+0000"
}
},
"user_attributes": {"Favourite_color": "Violet", "Pet_name": "Fluffy"},
"integration_ids": {"firebase_app_instance_id": "val1", "branch_id": "val2", "one_signal_player_id": "val3"},
"play_store_purchase_token": {
"product_id": "product_123",
"purchase_token": "token_abc_123",
"is_subscription": true
}
}

Event fields

Event parameters are the same for all event types.

FieldTypeDescription
advertising_idUUIDAdvertising ID (Android only).
attributionsJSONAttribution data. Included if Send Attribution is enabled in Webhook settings.
customer_user_idStringUser ID from your app (UUID, email, or other ID) if you set it in your app code when identifying users. If you don't identify users in the app code or this specific user is anonymous (not logged in), this field is null.
emailStringUser's email if you set it using the updateProfile method in the Adapty SDK or when creating/updating profiles via the server-side API. If you don't pass the email value to the SDK or API method, this field is null.
event_api_versionIntegerAdapty API version (current: 1).
event_datetimeISO 8601Event timestamp in ISO 8601 format (e.g., 2020-07-10T15:00:00.000000+0000).
event_propertiesJSONEvent properties.
event_typeStringEvent name in Adapty format. See Webhook event types for the full list.
idfaUUIDAdvertising ID (Apple only). IDFA in the profile in the Adapty Dashboard. It may be null if unavailable due to tracking restrictions, kids mode, or privacy settings.
idfvUUIDIdentifier for Vendors (IDFV), unique per developer. IDFV in the profile in the Adapty Dashboard.
integration_idsJSONUser integration IDs if you set them using the setIntegrationIdentifier method in the Adapty SDK or when creating/updating profiles via the server-side API. null if unavailable or integrations are disabled.
play_store_purchase_tokenJSONPlay Store purchase token, included if Send Play Store purchase token is enabled in Webhook settings.
profile_idUUIDProfile ID automatically generated by Adapty for each profile. One Apple/Google ID can be associated with different profile IDs if you don't identify users or allow purchases before login. Learn more about the way Adapty works with parent/inheritor profiles.
profile_install_datetimeISO 8601Installation timestamp in ISO 8601 format (e.g., 2020-07-10T15:00:00.000000+0000).
profiles_sharing_access_levelJSONList of users sharing the access level excluding the current user profile. If sharing access levels is enabled for your app, this list includes other profiles that have been used with the same Apple/Google ID.
Format:
  • profile_id: (UUID) Adapty ID
  • customer_user_id: (String) Customer User ID if provided
user_agentStringDevice browser user-agent.
user_attributesJSONCustom data you can set to enrich user profiles with app-specific information. Typically used to track user preferences (e.g., theme, language) or behavior flags (completed onboarding, feature usage).
Formatted as key-value pairs where keys are strings and values can be strings or numbers (e.g., {"Favourite_color": "Violet", "Pet_name": "Fluffy"}).
You can set custom attributes manually in the Adapty Dashboard for individual profiles, programmatically using the updateProfile method in the Adapty SDK, or via the server-side API when creating/updating profiles.
Included if Send User Attributes is enabled in Webhook settings.

While custom attribute values in the mobile app code can be set as floats or strings, attributes received via the server-side API or historical import may come in different formats. The boolean and integer values will be converted to floats in this case.

Attributions

To send the attribution data, enable the Send Attribution option in the Integrations -> Webhooks page. If you've enabled sending attribution data and if you have set up attribution integrations, the data below will be sent with the event for every source. The same attribution data is sent to all event types.

Json
{
"attributions": {
"appsflyer": {
"ad_set": "sample_ad_set_123",
"status": "non_organic",
"channel": "sample_channel",
"ad_group": "sample_ad_group_456",
"campaign": "sample_ios_campaign",
"creative": "sample_creative_789",
"created_at": "2000-01-31T00:00:00.000000+0000",
"network_user_id": "0000000000000-0000000"
}
}
}

Field nameField typeDescription
ad_setStringAttribution ad set.
statusStringCan be organic, non_organic, or unknown.
channelStringMarketing channel name.
ad_groupStringAttribution ad group.
campaignStringMarketing campaign name.
creativeStringAttribution creative keyword.
created_atISO 8601 dateDate and time of attribution record creation.
network_user_idStringID assigned to the user by the attribution source.

Integration IDs

The following integration IDs are used now in events:

  • adjust_device_id
  • airbridge_device_id
  • amplitude_device_id
  • amplitude_user_id
  • appmetrica_device_id
  • appmetrica_profile_id
  • appsflyer_id
  • branch_id
  • facebook_anonymous_id
  • firebase_app_instance_id
  • mixpanel_user_id
  • pushwoosh_hwid
  • one_signal_player_id
  • one_signal_subscription_id
  • tenjin_analytics_installation_id
  • posthog_distinct_user_id

Play Store purchase token

This field includes all the data needed to revalidate a purchase, if necessary. It is sent only if the Send Play Store purchase token option is enabled in the Webhook integration settings.

FieldTypeDescription
product_idStringThe unique identifier of the product (SKU) purchased in the Play Store.
purchase_tokenStringA token generated by Google Play to uniquely identify this purchase transaction.
is_subscriptionBooleanIndicates whether the purchased product is a subscription (true) or a one-time purchase (false).

Event properties

Event properties can vary depending on the event type and even between events of the same type. For instance, an event originating from the App Store won’t include Android-specific properties like base_plan_id.

The Access Level Updated event has distinct properties, so we’ve dedicated a separate section to it. Similarly, we’ve separated Additional tax and revenue event properties, as they are specific to only certain event types.

For most event types

The event properties for most event types are consistent (except for Access Level Updated event, which is described in its own section). Below is a comprehensive table highlighting properties and indicating if they belong to specific events.

FieldTypeDescription
ab_test_nameStringName of the Adapty A/B test where the transaction originated.
ab_test_revisionIntegerRevision of the A/B test where the transaction originated.
base_plan_idStringBase plan ID in the Google Play Store or price ID in Stripe.
cancellation_reasonString

Possible reasons for cancellation: voluntarily_cancelled, billing_error, price_increase, product_was_not_available, refund, cancelled_by_developer, new_subscription_replace, upgraded, unknown, adapty_revoked.

Present in the following event types:

subscription_cancelled, subscription_refunded, and trial_cancelled.
cohort_nameStringThe name of the audience that determined which paywall the user was shown.
consecutive_paymentsIntegerThe number of periods, that a user is subscribed to without interruptions. Includes the current period.
currencyStringLocal currency.
developer_idStringThe ID of the placement where the transaction originated.
environmentStringPossible values are Sandbox or Production.
event_datetimeISO 8601 dateThe date and time of the event. The same as on the root level of the event.
original_purchase_dateISO 8601 dateFor recurring subscriptions, the original purchase is the first transaction in the chain, its ID called original transaction ID links the chain of renewals; later transactions are extensions of it. The original purchase date is the date and time of this first transaction.
original_transaction_idString

For recurring subscriptions, this is the original transaction ID that links the chain of renewals. The original transaction is the first in the chain; later transactions are extensions of it.

If no extensions, original_transaction_id matches store_transaction_id.

paywall_nameStringName of the paywall where the transaction originated.
paywall_revisionStringRevision of the paywall where the transaction originated. The default value is 1.
price_localFloatProduct price before Apple/Google cut in local currency.
price_usdFloatProduct price before Apple/Google cut in USD.
profile_countryStringDetermined by Adapty, based on profile IP.
profile_event_idUUIDUnique event ID that can be used for deduplication.
profile_has_access_levelBooleanA boolean that indicates whether the profile has an active access level.
profile_idUUIDAdapty-generated profile ID. The same as on the root level of the event.
profile_ip_addressStringProfile IP (can be IPv4 or IPv6, with IPv4 preferred when available). null if Collect users' IP addresses is disabled in the app settings.
profile_total_revenue_usdFloatTotal revenue for the profile with refunds subtracted from the revenue.
promotional_offer_idStringThe Adapty ID of the promotional offer used. You set this ID when you create an offer in the dashboard.
purchase_dateISO 8601 dateThe date and time of the product purchase.
rate_after_first_yearBooleanBoolean indicates that the subscription qualifies for a reduced commission rate (typically 15%) after one year of continuous renewal. Commission rates vary based on program eligibility and country. See Store commission and taxes for details.
storeStringStore where the product was bought. Standard values: app_store, play_store, stripe, paddle.
If you set custom store transactions using the server-side API, the value from the store parameter is used.
store_countryStringThe country sent to us by the app store.
store_offer_categoryStringApplied offer category. Possible values are introductory, promotional, winback.
store_offer_discount_typeStringApplied offer type. Possible values are free_trial, pay_as_you_go, and pay_up_front.
subscription_expires_atISO 8601 dateThe Expiration date of subscription. Usually in the future.
transaction_idStringUnique identifier for a transaction.
trial_durationStringDuration of a trial period in days. Sent in a format " days", for example, "7 days". Present in the trial connected event types only: trial_started, trial_converted, trial_cancelled.
variation_idUUIDUnique ID of the paywall where the purchase was made.
vendor_product_idStringProduct ID in the Apple App Store, Google Play Store, or Stripe.

Additional tax and revenue event properties

The event properties related to taxes and revenue below are additional fields that apply only to certain event types. This means that the listed event types include the Event properties for most event types, along with the extra fields listed below.

Event types that have the tax and revenue event properties:

  • subscription_renewed
  • subscription_initial_purchase
  • subscription_refunded
  • non_subscription_purchase
FieldTypeDescription
net_revenue_localFloatNet revenue (income after Apple/Google cut and taxes) in local currency.
net_revenue_usdFloatNet revenue (income after Apple/Google cut and taxes) in USD.
proceeds_localFloatProduct price after Apple/Google cut in local currency.
proceeds_usdFloatProduct price after Apple/Google cut.
tax_amount_localFloatTax amount deducted in local currency.
tax_amount_usdFloatTax amount deducted in USD.

For Access Level Updated event

The Access Level Updated event is a specific webhook event generated only when the Webhook integration is active, and this event type is enabled. If enabled, it is sent to the configured Webhook and appears in the Event Feed. If not enabled, the event will not be created.

If you have enabled sharing access levels, the access level updated event will be sent for all profiles sharing the access level.

tip

Use this event to update the user’s access level in your database, grant or revoke premium features on your backend, and keep access in sync across devices or platforms.

PropertyTypeDescription
ab_test_nameStringName of the A/B test where the transaction originated.
access_level_idStringThe ID of the access level.
activated_atISO 8601 dateDate and time when the access was latest activated.
active_introductory_offer_typeStringType of introductory offer applied. Possible values are free_trial, pay_as_you_go, and pay_up_front.
active_promotional_offer_idStringID of promotional offer as indicated in the Product section of the Adapty Dashboard
active_promotional_offer_typeStringType of promotional offer applied. Possible values are free_trial, pay_as_you_go, and pay_up_front.
base_plan_idStringBase plan ID in the Google Play Store or price ID in Stripe.
billing_issue_detected_atISO 8601 dateDate and time of billing issue.
cancellation_reasonStringPossible reasons for cancellation: voluntarily_cancelled, billing_error, price_increase, product_was_not_available, refund, cancelled_by_developer, new_subscription_replace, upgraded, unknown, adapty_revoked.
cohort_nameStringName of the audience to which the profile belongs.
currencyStringLocal currency (defaults to USD).
developer_idStringThe ID of the placement where the transaction originated.
environmentStringPossible values are Sandbox or Production.
event_datetimeISO 8601 dateThe date and time of the event.
expires_atISO 8601 dateDate and time when the access will expire.
is_activeBooleanBoolean indicating whether the access level is active.
is_in_grace_periodBooleanBoolean indicating whether the profile is in the grace period.
is_lifetimeBooleanBoolean indicating whether the access level is lifetime.
is_refundBooleanBoolean indicating whether the transaction is a refund.
original_purchase_dateISO 8601 dateFor recurring subscriptions, the original purchase is the first transaction in the chain, its ID called original transaction ID links the chain of renewals; later transactions are extensions of it. The original purchase date is the date and time of this first transaction.
original_transaction_idString

For recurring subscriptions, this is the original transaction ID that links the chain of renewals. The original transaction is the first in the chain; later transactions are extensions of it.

If no extensions, original_transaction_id matches store_transaction_id.

The transaction identifier of the original purchase.
paywall_nameStringName of the paywall where the transaction originated.
paywall_revisionStringRevision of the paywall where the transaction originated. The default value is 1.
profile_countryStringDetermined by Adapty, based on profile IP.
profile_event_idUUIDUnique event ID that can be used for deduplication.
profile_has_access_levelBooleanBoolean indicating whether the profile has an active access level.
profile_idUUIDAdapty internal user profile ID.
profile_ip_addressStringProfile IP address of the user.
profile_total_revenue_usdFloatTotal revenue for the profile, refunds included.
purchase_dateISO 8601 dateThe date and time of product purchase.
renewed_atISO 8601 dateDate and time when the access will be renewed.
starts_atISO 8601 dateDate and time when the access level starts.
storeStringStore where the product was bought. Standard values: app_store, play_store, stripe, paddle.
If you set custom store transactions using the server-side API, the value from the store parameter is used.
store_countryStringCountry sent to Adapty by the app store.
subscription_expires_atISO 8601 dateExpiration date of the subscription.
transaction_idStringUnique identifier for a transaction.
trial_durationStringDuration of a trial period in days (e.g., "7 days").
variation_idUUIDAn identifier of a variation, used to attribute purchases to this paywall.
vendor_product_idStringProduct ID in the store (Apple/Google/Stripe).
will_renewBooleanIndicates whether the paid access level will be renewed.
warning

Note that this structure may grow over time — with new data being introduced by us or by the 3rd parties we work with. Make sure that your code that processes it is robust enough and relies on specific fields rather than the entire structure.