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 TypeDescriptionApp StorePlay StoreAmazonStripePromo
TESTTest event issued through the RevenueCat dashboard.
INITIAL_PURCHASEA new subscription has been purchased.
RENEWALAn existing subscription has been renewed or a lapsed user has resubscribed.
CANCELLATIONA 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.
UNCANCELLATIONA non-expired cancelled subscription has been re-enabled.
NON_RENEWING_PURCHASEA customer has made a purchase that will not auto-renew.
SUBSCRIPTION_PAUSEDThe 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)
EXPIRATIONA 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_ISSUEThere 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_CHANGEA 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.
TRANSFERA 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_EXTENDEDAn 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

FieldTypeDescriptionPossible Values
typeStringType of the event.TEST

INITIAL_PURCHASE

NON_RENEWING_PURCHASE

RENEWAL

PRODUCT_CHANGE

CANCELLATION

BILLING_ISSUE

SUBSCRIBER_ALIAS

SUBSCRIPTION_PAUSED

UNCANCELLATION

TRANSFER

SUBSCRIPTION_EXTENDED
idStringUnique identifier of the event.
app_idStringUnique 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_msIntegerThe time that the event was generated. Does not necessarily coincide with when the action that triggered the event occurred (purchased, cancelled, etc).
app_user_idStringLast seen app user id of the subscriber.
original_app_user_idStringThe first app user id used by the subscriber.
aliasesArrayk:parameAll 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 the aliases array.

📘

If we have to retry a webhook for any reason, the retry will have the same id and event_timestamp_ms of the first attempt.

Subscription Lifecycle Events Fields

FieldTypeDescriptionPossible Values
product_idStringProduct 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_idsArrayk:parameEntitlement identifiers of the subscription.It can be NULL if the product_id is not mapped to any entitlements.
entitlement_idStringDeprecated. See entitlement_ids.Deprecated. See entitlement_ids.
period_typeStringPeriod 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_msIntegerTime when the transaction was purchased. Measured in milliseconds since Unix epoch
grace_period_expiration_at_msIntegerOnly 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_msIntegerExpiration 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_msIntegerThe 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.
storeStringStore the subscription belongs to.AMAZON

APP_STORE

MAC_APP_STORE

PLAY_STORE

PROMOTIONAL

STRIPE
environmentStringStore environment.SANDBOX

PRODUCTION
is_trial_conversionBooleanOnly available for RENEWAL events.

Whether the previous transaction was a free trial or not.
true or false
cancel_reasonStringOnly available for CANCELLATION events.

See Cancellation and Expiration Reasons.
UNSUBSCRIBE

BILLING_ERROR

DEVELOPER_INITIATED

PRICE_INCREASE

CUSTOMER_SUPPORT

UNKNOWN
expiration_reasonStringOnly available for EXPIRATION events.

See Cancellation and Expiration Reasons.
UNSUBSCRIBE

BILLING_ERROR

DEVELOPER_INITIATED

PRICE_INCREASE

CUSTOMER_SUPPORT

UNKNOWN
new_product_idStringProduct identifier of the new product the subscriber has switched to. Only available for App Store subscriptions and PRODUCT_CHANGE events.
presented_offering_idStringNot 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.
priceDoubleThe USD price of the transaction.Can be NULL if the price is unknown, and 0 for free trials.

Can be negative for refunds.
currencyStringThe ISO 4217 currency code that the product was purchased in.USD, CAD, etc.

Can be NULL if the currency is unknown.
price_in_purchased_currencyDoubleThe 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_percentageDoubleThe 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_percentageDoubleThe 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_percentageDoubleDEPRECATED: 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_attributesMap of attribute names to attribute objects.

For more details see the subscriber attributes guide.
transaction_idStringTransaction identifier from Apple/Amazon/Google/Stripe.
original_transaction_idStringtransaction_id of the original transaction in the subscription from Apple/Amazon/Google/Stripe.
is_family_shareBooleanIndicates 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_fromString[]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_toString[]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_codeStringThe 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_codeStringThis 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 /subscribersendpoint with the app_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

ReasonDescriptionApp StorePlay StoreAmazonWebPromo
UNSUBSCRIBESubscriber cancelled voluntarily. This event fires when a user unsubscribes, not when the subscription expires.
BILLING_ERRORApple, 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_INITIATEDDeveloper cancelled the subscription.
PRICE_INCREASESubscriber did not agree to a price increase.
CUSTOMER_SUPPORTCustomer 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.
UNKNOWNApple did not provide the reason of the cancellation.
SUBSCRIPTION_PAUSEDThe subscription expired because it was paused (only EXPIRATION event)