Event Types and Fields
The types of webhooks sent from RevenueCat
RevenueCat sends webhooks in response to events that occur in your app. Here these event types are defined, as well as the data contained in each webhook.
Event Types
Webhook Event Type | Description | App Store | Play Store | Amazon | Stripe | Promo |
---|---|---|---|---|---|---|
TEST | Test event issued through the RevenueCat dashboard. | ✅ | ✅ | ❌ | ❌ | ❌ |
INITIAL_PURCHASE | A new subscription has been purchased. | ✅ | ✅ | ✅ | ✅ | ❌ |
RENEWAL | An existing subscription has been renewed or a lapsed user has resubscribed. | ✅ | ✅ | ✅ | ✅ | ❌ |
CANCELLATION | A subscription or non-renewing purchase has been cancelled or refunded. Note that in the event of refunds, a subscription's auto-renewal setting may still be active. See cancellation reasons for more details. | ✅ | ✅ | ✅ | ✅ | ✅ |
UNCANCELLATION | A non-expired cancelled subscription has been re-enabled. | ✅ | ✅ | ✅ | ❌ | ❌ |
NON_RENEWING_PURCHASE | A customer has made a purchase that will not auto-renew. | ✅ | ✅ | ✅ | ✅ | ✅ |
SUBSCRIPTION_PAUSED | The subscription has set to be paused at the end of the period. Please note: You should not revoke access when receiving a SUBSCRIPTION_PAUSED event, but only when receiving an EXPIRATION event (which will have the expiration reason SUBSCRIPTION_PAUSED ) | ❌ | ✅ | ❌ | ❌ | ❌ |
EXPIRATION | A subscription has expired and access should be removed. If you have Platform Server Notifications configured, this event will occur as soon as we are notified (within seconds to minutes) of the expiration. If you do not have notifications configured, delays may be approximately 1 hour. | ✅ | ✅ | ✅ | ✅ | ✅ |
BILLING_ISSUE | There has been a problem trying to charge the subscriber. This does not mean the subscription has expired. Can be safely ignored if listening to CANCELLATION event + cancel_reason=BILLING_ERROR . | ✅ | ✅ | ✅ | ✅ | ❌ |
PRODUCT_CHANGE | A subscriber has changed the product of their subscription. This does not mean the new subscription is in effect immediately. See Managing Subscriptions for more details on updates, downgrades, and crossgrades. | ✅ | ✅ | ❌ | ✅ | ❌ |
TRANSFER | A transfer of transactions and entitlements was initiated between one App User ID(s) to another. Please note: The webhook will only be sent for the destination user despite us displaying this event in both customer histories because the event body is exactly the same for both users. | ✅ | ✅ | ✅ | ✅ | ❌ |
SUBSCRIPTION_EXTENDED | An existing subscription has been extended (the expiration date of the current subscription period has been pushed back to the future). This event is fired when a Apple App Store or Google Play Store subscription is extended through the store's API. On the Google Play Store, this event can also sometimes fire when Google defers charging for a renewal by less than 24 hours (for unknown reasons). In this case, you will receive a SUBSCRIPTION_EXTENDED webhook, followed by either a RENEWAL or BILLING_ISSUE webhook within the next 24 hours. | ✅ | ✅ | ❌ | ✅ | ❌ |
Events Format
Webhook events are serialized in JSON. The body of a POST
request to your server will contain the serialized event, as well as the API version.
{
"api_version": "1.0",
"event": {
"aliases": [
"yourCustomerAliasedID",
"yourCustomerAliasedID"
],
"app_id": "yourAppID",
"app_user_id": "yourCustomerAppUserID",
"commission_percentage": 0.3,
"country_code": "US",
"currency": "USD",
"entitlement_id": "pro_cat",
"entitlement_ids": [
"pro_cat"
],
"environment": "PRODUCTION",
"event_timestamp_ms": 1591121855319,
"expiration_at_ms": 1591726653000,
"id": "UniqueIdentifierOfEvent",
"is_family_share": false,
"offer_code": "free_month",
"original_app_user_id": "OriginalAppUserID",
"original_transaction_id": "1530648507000",
"period_type": "NORMAL",
"presented_offering_id": "OfferingID",
"price": 2.49,
"price_in_purchased_currency": 2.49,
"product_id": "onemonth_no_trial",
"purchased_at_ms": 1591121853000,
"store": "APP_STORE",
"subscriber_attributes": {
"$Favorite Cat": {
"updated_at_ms": 1581121853000,
"value": "Garfield"
}
},
"takehome_percentage": 0.7,
"tax_percentage": 0.3,
"transaction_id": "170000869511114",
"type": "INITIAL_PURCHASE"
}
}
Common Fields
Field | Type | Description | Possible Values |
---|---|---|---|
type | String | Type of the event. | TEST INITIAL_PURCHASE NON_RENEWING_PURCHASE RENEWAL PRODUCT_CHANGE CANCELLATION BILLING_ISSUE SUBSCRIBER_ALIAS SUBSCRIPTION_PAUSED UNCANCELLATION TRANSFER SUBSCRIPTION_EXTENDED |
id | String | Unique identifier of the event. | |
app_id | String | Unique identifier of the app the event is associated with. Corresponds to an app within a project. This value will soon be visible in the app's configuration page in project settings. | |
event_timestamp_ms | Integer | The time that the event was generated. Does not necessarily coincide with when the action that triggered the event occurred (purchased, cancelled, etc). | |
app_user_id | String | Last seen app user id of the subscriber. | |
original_app_user_id | String | The first app user id used by the subscriber. | |
aliases | Arrayk:parame | All app user ids ever used by the subscriber. |
When looking up users from the webhook in your systems, make sure to search both the
original_app_user_id
and thealiases
array.
If we have to retry a webhook for any reason, the retry will have the same
id
andevent_timestamp_ms
of the first attempt.
Subscription Lifecycle Events Fields
Field | Type | Description | Possible Values |
---|---|---|---|
product_id | String | Product identifier of the subscription. Please note: For Google Play products set up in RevenueCat after February 2023, this identifier has the format <subscription_id>:<base_plan_id> | |
entitlement_ids | Arrayk:parame | Entitlement identifiers of the subscription. | It can be NULL if the product_id is not mapped to any entitlements. |
entitlement_id | String | Deprecated. See entitlement_ids . | Deprecated. See entitlement_ids . |
period_type | String | Period type of the transaction. | TRIAL , for free trials.INTRO , for introductory pricing.NORMAL , standard subscription.PROMOTIONAL , for subscriptions granted through RevenueCat.PREPAID ,for Play Store prepaid transactions . |
purchased_at_ms | Integer | Time when the transaction was purchased. Measured in milliseconds since Unix epoch | |
grace_period_expiration_at_ms | Integer | Only available for BILLING_ISSUE events.The time that the grace period for the subscription would expire. Measured in milliseconds since Unix epoch. Use this field to determine if the user is currently in a grace period. | It can be NULL if subscription does not have a grace period. |
expiration_at_ms | Integer | Expiration of the transaction. Measured in milliseconds since Unix epoch. Use this field to determine if a subscription is still active. | It can be NULL for non-subscription purchases. |
auto_resume_at_ms | Integer | The time when an Android subscription would resume after being paused. Measured in milliseconds since Unix epoch. Only available for Play Store subscriptions and SUBSCRIPTION_PAUSED events. | |
store | String | Store the subscription belongs to. | AMAZON APP_STORE MAC_APP_STORE PLAY_STORE PROMOTIONAL STRIPE |
environment | String | Store environment. | SANDBOX PRODUCTION |
is_trial_conversion | Boolean | Only available for RENEWAL events.Whether the previous transaction was a free trial or not. | true or false |
cancel_reason | String | Only available for CANCELLATION events.See Cancellation and Expiration Reasons. | UNSUBSCRIBE BILLING_ERROR DEVELOPER_INITIATED PRICE_INCREASE CUSTOMER_SUPPORT UNKNOWN |
expiration_reason | String | Only available for EXPIRATION events.See Cancellation and Expiration Reasons. | UNSUBSCRIBE BILLING_ERROR DEVELOPER_INITIATED PRICE_INCREASE CUSTOMER_SUPPORT UNKNOWN |
new_product_id | String | Product identifier of the new product the subscriber has switched to. Only available for App Store subscriptions and PRODUCT_CHANGE events. | |
presented_offering_id | String | Not available for apps using legacy entitlements. The identifier for the offering that was presented to the user during their initial purchase. | Can be NULL if the purchase was made using purchaseProduct instead of purchasePackage or if the purchase was made outside of your app or before you integrated RevenueCat. |
price | Double | The USD price of the transaction. | Can be NULL if the price is unknown, and 0 for free trials.Can be negative for refunds. |
currency | String | The ISO 4217 currency code that the product was purchased in. | USD , CAD , etc.Can be NULL if the currency is unknown. |
price_in_purchased_currency | Double | The price of the transaction in the currency the product was purchased in. | Can be NULL if the price is unknown, and 0 for free trials.Can be negative for refunds. |
tax_percentage | Double | The estimated percentage of the transaction price that was deducted for taxes (varies by country and store). | Can be NULL if the tax percentage is unknown. |
commission_percentage | Double | The estimated percentage of the transaction price that was deducted as a store commission / processing fee. | Can be NULL if the commission percentage is unknown. |
takehome_percentage | Double | DEPRECATED: The estimated percentage of the transaction price that will be paid out to developers after commissions, but before VAT and DST taxes are taken into account. We recommend using tax_percentage and commission_percentage to calculate proceeds instead. Learn more here. | |
subscriber_attributes | Map of attribute names to attribute objects. For more details see the subscriber attributes guide. | ||
transaction_id | String | Transaction identifier from Apple/Amazon/Google/Stripe. | |
original_transaction_id | String | transaction_id of the original transaction in the subscription from Apple/Amazon/Google/Stripe. | |
is_family_share | Boolean | Indicates if the user made this purchase or if it was shared to them via Family Sharing. | true or false Always false for non-Apple purchases. |
transferred_from | String[] | This fields is only available when type is set to TRANSFER .App User ID(s) that transactions and entitlements are being taken from, and granted to transferred_to . | |
transferred_to | String[] | This field is only available when type is set to TRANSFER .App User ID(s) that are receiving the transactions and entitlements taken from transferred_from . | |
country_code | String | The ISO 3166 country code that the product was purchased in. The two-letter country code (e.g., US, GB, CA) of the app user's location (this country code is derived from the last seen request from the SDK for the subscriber.) | US , CA , etc. |
offer_code | String | This field is not available when type is set to SUBSCRIBER_ALIAS or TRANSFER .The offer code that the customer used to redeem the transaction. Available for App Store and Play Store. For App Store this property corresponds to the offer_code_ref_name . For Play Store this corresponds to the promotionCode . | Can be null if no offer code was used for this product. |
To get the RevenueCat event
id
from a Subscription Lifecycle webhook, simply make an API call to our GET/subscribers
endpoint with theapp_user_id
after receiving the webhook and look for the latest purchase in the subscription/non-subscription object.
Determine trial and subscription duration
To get a trial or subscription's duration from a webhook, you can subtract purchased_at_ms from expiration_at_ms and you will get the duration of the trial in milliseconds.
Cancellation and Expiration Reasons
Reason | Description | App Store | Play Store | Amazon | Web | Promo |
---|---|---|---|---|---|---|
UNSUBSCRIBE | Subscriber cancelled voluntarily. This event fires when a user unsubscribes, not when the subscription expires. | ✅ | ✅ | ✅ | ✅ | ❌ |
BILLING_ERROR | Apple, Amazon, or Google could not charge the subscriber using their payment method. The CANCELLATION event with cancellation reason BILLING_ERROR is fired as soon as the billing issue has been detected. The EXPIRATION event with expiration reason BILLING_ERROR is fired if the grace period (if set up) has ended without recovering the payment, and the customer should lose access to the subscription. | ✅ | ✅ | ✅ | ❌ | ❌ |
DEVELOPER_INITIATED | Developer cancelled the subscription. | ✅ | ✅ | ❌ | ❌ | ✅ |
PRICE_INCREASE | Subscriber did not agree to a price increase. | ✅ | ❌ | ❌ | ❌ | ❌ |
CUSTOMER_SUPPORT | Customer received a refund from Apple support, a Play Store subscription was refunded through RevenueCat, an Amazon subscription was refunded through Amazon support, or a web subscription was refunded. Note that this does not mean that a subscription's autorenewal preference has been deactivated since refunds can be given without cancelling a subscription. You should check the current subscription status to check if the subscription is still active. | ✅ | ✅ | ✅ | ✅ | ❌ |
UNKNOWN | Apple did not provide the reason of the cancellation. | ✅ | ❌ | ❌ | ❌ | ❌ |
SUBSCRIPTION_PAUSED | The subscription expired because it was paused (only EXPIRATION event) | ❌ | ✅ | ❌ | ❌ | ❌ |
Updated 7 days ago