Skip to main content
Skip to navigation

Event Types and Fields

The types of webhooks sent from RevenueCat

AIAsk AIChatGPTClaude

RevenueCat sends webhooks in response to events that occur in your app. This page defines those event types and the data contained in each webhook.

For sample payloads, see Sample webhook events.

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"
}
}

Event types

Each group of events below links to its field descriptions, lists its event descriptions, and then displays a table showing store compatibility or feature availability ( = supported, = not supported).

Dashboard test

Applicable fields: Common fields · Subscriber identity · Subscription lifecycle

  • TEST — RevenueCat issued a test event.
    • This event uses a purchase-like sample payload and isn't persisted in production.
Webhook Event TypeApp StoreGoogle PlayAmazonStripePromoRokuRevenueCat Billing
TEST

Subscription lifecycle purchases

Applicable fields: Common fields · Subscriber identity · Subscription lifecycle

  • INITIAL_PURCHASE — A new subscription was purchased.
  • RENEWAL — An existing subscription was renewed, or a lapsed user resubscribed.
  • CANCELLATION — A subscription or non-renewing purchase was canceled or refunded.
    • In the case of refunds, a subscription's auto-renewal setting may still be active. See cancellation reasons for more details.
    • In the case of subscription refunds, this event fires only when the latest subscription period is refunded; refunds for earlier periods do not trigger it.
  • UNCANCELLATION — A non-expired canceled subscription was re-enabled.
  • NON_RENEWING_PURCHASE — A customer has made a purchase that won't auto-renew.
  • SUBSCRIPTION_PAUSED — The subscription was scheduled to pause at the end of the current period.
    • Don't revoke access on this event. Revoke access only on EXPIRATION with expiration reason SUBSCRIPTION_PAUSED.
  • EXPIRATION — A subscription has expired.
    • The associated user's access should be removed.
    • With Platform Server Notifications configured, this event occurs within seconds to minutes of expiration. Without notifications, the event might be delayed by approximately 1 hour.
  • BILLING_ISSUE — An attempt to charge the subscriber failed.
    • This doesn't mean the subscription has expired.
    • You can safely ignore this event if you listen for CANCELLATION with cancel_reason=BILLING_ERROR.
  • PRODUCT_CHANGE — A subscriber has changed the product of their subscription.
    • This doesn't mean the new subscription is in effect immediately. See Managing Subscriptions for more details on updates, downgrades, and crossgrades.
    • For Stripe subscriptions using Products identified by a Stripe Price ID, switching to a different Price of the same Stripe Product is also reported as a product change, because each Price maps to a distinct product in RevenueCat. See how Stripe identifiers appear in exports.
  • SUBSCRIPTION_EXTENDED — An existing subscription was extended.
    • The expiration date of the current subscription period was pushed back.
    • This event is fired when an App Store or Google Play subscription is extended through the store's API.
    • On Google Play, this event can also fire when Google defers charging for a renewal by less than 24 hours (for unknown reasons). You may then receive RENEWAL or BILLING_ISSUE within the next 24 hours.
  • REFUND_REVERSED — A refund was reversed.
  • INVOICE_ISSUANCE — A new, unpaid invoice was issued.
    • A new invoice was created for a subscription or non-renewing purchase that hasn't yet been paid.
    • This only applies to RevenueCat Billing purchases, both for new checkout purchases and subscription renewals.
Webhook Event TypeApp StoreGoogle PlayAmazonStripePromoRokuRevenueCat Billing
INITIAL_PURCHASE
RENEWAL
CANCELLATION
UNCANCELLATION
NON_RENEWING_PURCHASE
SUBSCRIPTION_PAUSED
EXPIRATION
BILLING_ISSUE
PRODUCT_CHANGE
SUBSCRIPTION_EXTENDED
REFUND_REVERSED
INVOICE_ISSUANCE

Transfer

Applicable fields: Common fields · Transfer

  • TRANSFER — A transfer of transactions and entitlements was initiated between App User ID(s).
    • The webhook is sent only for the destination user, although the event appears in both customer histories. The event body is identical for both users.
    • When a transfer webhook is sent, a separate PURCHASE_REDEEMED webhook might also be sent for Paddle, RevenueCat Billing, or Stripe redemptions that result in a transfer.
Webhook Event TypeApp StoreGoogle PlayAmazonStripePromoRokuRevenueCat Billing
TRANSFER

Temporary entitlement grant

Applicable fields: Common fields · Temporary entitlement grant

  • TEMPORARY_ENTITLEMENT_GRANT — RevenueCat issued a temporary outage grant to a customer.
    • RevenueCat was temporarily unable to validate a purchase with the store and granted a short-term entitlement (at most 24 hours). This prevents customers from being denied access during exceptional situations, such as partial app store outages.
    • After connectivity is restored, if validation succeeds, expect a regular INITIAL_PURCHASE. If validation fails, expect an EXPIRATION event for the temporary entitlement grant.
    • Because this event is dispatched during limited connectivity, it contains less information than a regular purchase event. In particular, it excludes subscription lifecycle or subscriber identity fields beyond app_user_id.
Webhook Event TypeApp StoreGoogle PlayAmazonStripePromoRokuRevenueCat Billing
TEMPORARY_ENTITLEMENT_GRANT

In-app currency transaction

Applicable fields: Common fields · Subscriber identity · In-app currency transaction

  • VIRTUAL_CURRENCY_TRANSACTION — An in-app currency transaction occurred.
    • Purchases and refunds can both trigger this event.
    • For subscriptions that grant in-app currency, this event is sent for the entire subscription lifecycle whenever there is an adjustment to be made to the currency balance. This includes the initial purchase, renewals, and refunds.
    • This event provides details about the in-app currency adjustment, including the amount, currency type, and source of the change.
Webhook Event TypeApp StoreGoogle PlayAmazonStripePromoRokuRevenueCat Billing
VIRTUAL_CURRENCY_TRANSACTION

Experiment enrollment

Applicable fields: Common fields · Subscriber identity · Experiment enrollment

  • EXPERIMENT_ENROLLMENT — A customer was enrolled in an experiment.
    • This event isn't associated with a store.
    • app_id is usually excluded. It is included only when enrollment is linked to a dashboard store app (for example, when the SDK has reported last-seen app config data).
Webhook Event TypeApp StoreGoogle PlayAmazonStripePromoRokuRevenueCat Billing
EXPERIMENT_ENROLLMENT

Purchase redemption

Applicable fields: Common fields · Purchase redemption

  • PURCHASE_REDEEMED — A Paddle, RevenueCat Billing, or Stripe purchase was redeemed and associated with an App User ID.
    • This fires when a user opens a redemption deep link in your app.
    • If the redemption results in a transfer, this is fired in addition to TRANSFER.
Webhook Event TypeApp StoreGoogle PlayAmazonStripePaddlePromoRokuRevenueCat Billing
PURCHASE_REDEEMED

Subscriber alias

Applicable fields: Common fields · Subscriber identity

  • SUBSCRIBER_ALIASDeprecated. A new App User ID was registered for an existing subscriber.
    • This is a legacy event type. New projects don't receive this webhook.
Webhook Event TypeApp StoreGoogle PlayAmazonStripePromoRokuRevenueCat Billing
SUBSCRIBER_ALIAS

Applicable fields: Common fields · Subscriber identity · Price increase consent

  • PRICE_INCREASE_CONSENT_REQUIRED — A price increase requires customer consent before the subscription can renew at the new price.
  • PRICE_INCREASE_CONSENT_APPROVED — A customer consented to a pending price increase.
Webhook Event TypeApp StoreGoogle PlayAmazonStripePromoRokuRevenueCat Billing
PRICE_INCREASE_CONSENT_REQUIRED
PRICE_INCREASE_CONSENT_APPROVED

Fields

The event fields are grouped into related attributes and referenced from the event type groups above. Use the Included column when building parsers:

  • Always — The JSON key is always included for the listed event types, but the value may still be null.
  • Sometimes — The key is only included when data is available; it may be omitted entirely from the payload.
  • (blank) — Nested field under a parent array or object. See the parent row for when the key is included.

Parse defensively: treat Sometimes fields as optional keys, and don't assume Always fields are non-null. Some event types omit fields listed in a group, as noted in each section.

Common fields

Applicable events: All event types, including Dashboard test.

These fields are on every webhook payload. api_version is at the root of the POST body; the rest are inside the event object. If HMAC signing is enabled, retries recompute the X-RevenueCat-Webhook-Signature header. See Signature timestamp on retries.

FieldTypeDescriptionIncluded
api_versionStringAPI version of the webhook format.Always
typeStringType of the event.Always
idStringUnique identifier of the event. Retries reuse the same id and event_timestamp_ms.Always
event_timestamp_msIntegerThe time that the event was generated, which doesn't necessarily coincide with when the action that triggered the event occurred. Retries reuse the same id and event_timestamp_ms.Always
app_idStringPublic identifier of the dashboard app (store configuration) associated with the event. Found in project settings.Always, except when store is PROMOTIONAL or when the event has no linked app configuration (e.g. EXPERIMENT_ENROLLMENT).

Subscriber identity fields

Applicable events: Dashboard test · Subscription lifecycle purchases · In-app currency transaction · Experiment enrollment · Subscriber alias · Price increase consent.

When looking up users from the webhook in your systems, make sure to search both the original_app_user_id and the aliases array.

FieldTypeDescriptionIncluded
app_user_idStringLast seen App User ID of the subscriber.Always
original_app_user_idStringThe first App User ID used by the subscriber.Always
aliasesArrayAll App User IDs ever used by the subscriber.Always
subscriber_attributesMapMap of attribute names to attribute objects. See the customer attributes guide.Sometimes
experimentsArrayExperiments the subscriber was enrolled in at event time. Each entry has the attributes listed below.Sometimes
experiments[].experiment_idStringID of the experiment.
experiments[].experiment_variantStringVariant the subscriber was enrolled in.
experiments[].enrolled_at_msIntegerWhen the subscriber was enrolled, in milliseconds since Unix epoch. This can be null.

VIRTUAL_CURRENCY_TRANSACTION doesn't use this field group as written above. When data is available, app_user_id, aliases, and subscriber_attributes might be included (Sometimes). original_app_user_id and experiments aren't included. See In-app currency transaction fields.

Subscription lifecycle fields

Applicable events: Dashboard test · Subscription lifecycle purchases.

FieldTypeDescriptionIncluded
product_idStringProduct identifier of the subscription. For Google Play products set up in RevenueCat after February 2023, this identifier has the format <subscription_id>:<base_plan_id>.Always
period_typeStringPeriod type of the transaction: TRIAL, INTRO, NORMAL, PROMOTIONAL, or PREPAID.Always
purchased_at_msIntegerTime when the transaction was purchased, in milliseconds since Unix epoch.Always
expiration_at_msIntegerExpiration of the transaction, in milliseconds since Unix epoch. This can be null for non-subscription purchases or lifetime products.Always
environmentStringStore environment: SANDBOX or PRODUCTION.Always
entitlement_idStringDeprecated. See entitlement_ids.Always
entitlement_idsArrayEntitlement identifiers of the subscription. This can be null if the product_id is not mapped to any entitlements.Always
presented_offering_idStringOffering presented during the initial purchase. This can be null. Not available for apps using legacy entitlements.Always
transaction_idStringTransaction identifier from the store.Always
original_transaction_idStringtransaction_id of the original transaction in the subscription.Always
is_family_shareBooleanWhether the purchase was shared via Family Sharing. This is always false for purchases made outside the App Store.Always
country_codeStringISO 3166-1 Alpha-2 country code derived from the subscriber's last seen location: US, CA, etc.Always
storeStringStore the purchase belongs to: AMAZON, APP_STORE, MAC_APP_STORE, PADDLE, PLAY_STORE, PROMOTIONAL, RC_BILLING, ROKU, STRIPE, TEST_STORESometimes
currencyStringISO 4217 currency code. Can be null if unknown: USD, CAD, etc.Sometimes
priceDoubleUSD price of the transaction. This can be null if unknown, 0 for free trials, or negative for refunds.Sometimes
price_in_purchased_currencyDoublePrice in the purchase currency. This can be null if unknown, 0 for free trials, or negative for refunds.Sometimes
tax_percentageDoubleEstimated tax percentage deducted from the transaction. This can be null if unknown.Sometimes
commission_percentageDoubleEstimated store commission percentage. This can be null if unknown.Sometimes
takehome_percentageDoubleDeprecated. Use tax_percentage and commission_percentage instead. Learn more.Sometimes
offer_codeStringOffer or promotion code used for the transaction. This can be null. Available for App Store and Google Play.Sometimes
renewal_numberIntegerNumber of renewals this subscription has gone through. Starts at 1; trial conversions count as renewals.Sometimes
metadataObjectDeveloper-defined metadata attached to RevenueCat Billing transaction.Sometimes
discount_percentageDoubleDiscount percentage applied to the transaction.Sometimes
discount_amountDoubleDiscount amount applied to the transaction.Sometimes
discount_identifierStringIdentifier of the discount applied to the transaction.Sometimes
quantityIntegerQuantity purchased. This is only included in NON_RENEWING_PURCHASE for some projects.Sometimes
grace_period_expiration_at_msIntegerGrace period expiration. This is only included on BILLING_ISSUE and always present on that event type. This can be null.Sometimes
auto_resume_at_msIntegerWhen a paused Google Play subscription resumes. This is only included on SUBSCRIPTION_PAUSED and always present on that event type.Sometimes
is_trial_conversionBooleanWhether the previous period was a free trial. This is only included on RENEWAL.Sometimes
cancel_reasonStringReason for CANCELLATION. This isn't included on other events. See Cancellation and Expiration Reasons.Sometimes
expiration_reasonStringReason for EXPIRATION. This isn't included on other events. See Cancellation and Expiration Reasons: UNSUBSCRIBE, BILLING_ERROR, DEVELOPER_INITIATED, PRICE_INCREASE, CUSTOMER_SUPPORT, UNKNOWN, SUBSCRIPTION_PAUSEDSometimes
new_product_idStringProduct the subscriber switched to. This is only included on PRODUCT_CHANGE for App Store, deferred Google Play changes, and RevenueCat Billing (where product_id is the product the subscriber switched from). This is omitted from the payload when null.Sometimes

discount_percentage, discount_amount, and discount_identifier apply only to INITIAL_PURCHASE, RENEWAL, and NON_RENEWING_PURCHASE within Subscription lifecycle purchases.

📘Determine trial and subscription duration

Subtract purchased_at_ms from expiration_at_ms to get the period duration in milliseconds.

📘App Store renewal timestamps

For App Store renewals, Apple may charge up to 24 hours before the billing period starts, so purchased_at_ms (billing period start) can be later than event_timestamp_ms (when payment was collected).

Transfer fields

Applicable events: Transfer.

FieldTypeDescriptionIncluded
transferred_fromString[]App User ID(s) transactions and entitlements are taken from.Always
transferred_toString[]App User ID(s) receiving the transactions and entitlements.Always
subscriber_attributesMapSubscriber attributes for the destination subscriber.Sometimes
storeStringStore of the transferred purchases.Sometimes
environmentStringStore environment.Sometimes

Temporary entitlement grant fields

Applicable events: Temporary entitlement grant.

FieldTypeDescriptionIncluded
app_user_idStringApp User ID of the subscriber who received the temporary grant.Always
storeStringStore of the purchase.Sometimes

After the outage resolves, expect a regular INITIAL_PURCHASE or EXPIRATION event for the temporary entitlement grant.

In-app currency transaction fields

Applicable events: In-app currency transaction.

FieldTypeDescriptionIncluded
sourceStringSource of the in-app currency adjustment: in_app_purchase, admin_api, server_api, client_sdk, expiration, ad_rewardSometimes
virtual_currency_transaction_idStringUnique identifier for this in-app currency transaction.Sometimes
adjustmentsArrayIn-app currency balance changes in this transaction. Each entry has the attributes listed below.Sometimes
adjustments[].amountIntegerAmount added (positive) or removed (negative) from the customer's balance for this currency.
adjustments[].currencyObjectDetails about the in-app currency involved in the adjustment.
adjustments[].currency.codeStringUnique identifier for the in-app currency.
adjustments[].currency.nameStringDisplay name of the in-app currency.
adjustments[].currency.descriptionStringDescription of the in-app currency.
product_idStringIn-app purchase product identifier. Populated when source is in_app_purchase.Sometimes
product_display_nameStringDisplay name of the product. Populated when source is in_app_purchase.Sometimes
transaction_idStringIn-app purchase transaction identifier. Populated when source is in_app_purchase.Sometimes
storeStringStore of the in-app purchase. Populated when source is in_app_purchase: AMAZON, APP_STORE, MAC_APP_STORE, PLAY_STORE, RC_BILLING, STRIPESometimes
purchase_environmentStringEnvironment of the in-app purchase: SANDBOX, PRODUCTION. Populated when source is in_app_purchase.Sometimes
updated_balanceIntegerCustomer balance after the adjustment.Sometimes
ad_transaction_idStringClient transaction ID for ad reward verification. Populated only when source is ad_reward.Sometimes

Experiment enrollment event fields

Applicable events: Experiment enrollment.

This event type usually has no linked dashboard store app, so app_id is typically omitted from the payload. When enrollment is tied to a store app configuration, app_id is included with the public identifier of that app.

FieldTypeDescriptionIncluded
experiment_idStringID of the experiment the customer was enrolled in.Always
experiment_variantStringVariant the customer was enrolled in.Always
experiment_enrolled_at_msIntegerWhen the customer was enrolled, in milliseconds since Unix epoch.Always
offering_idStringOffering ID of the enrolled variant.Sometimes
country_codeStringISO 3166-1 Alpha-2 country code for the enrollment.Sometimes

Purchase redemption event fields

Applicable events: Purchase redemption.

When redemption_outcome is transfer, a TRANSFER webhook is also sent for the destination user.

FieldTypeDescriptionIncluded
redeemed_fromString[]App User ID(s) of the original web purchaser.Sometimes
redeemed_byString[]App User ID(s) of the redeemer.Sometimes
redemption_outcomeStringHow the redemption was resolved: alias, transfer, redeemer_ownsSometimes
redemption_platformStringPlatform of the redeem request (from the SDK X-Platform header): ios, android, macos, amazon, web, etc. (lowercase). This can be null.Sometimes
storeStringStore of the redeemed purchase: PADDLE, RC_BILLING, STRIPESometimes
environmentStringEnvironment of the redeemed purchase: SANDBOX, PRODUCTIONSometimes
product_idStringProduct identifier of the redeemed purchase. This can be null.Sometimes
entitlement_idsArrayEntitlements associated with the redeemed purchase. This can be null.Sometimes
workflow_idStringFunnel workflow ID, if the purchase originated from a Funnel.Sometimes
workflow_step_idStringFunnel step ID that triggered checkout.Sometimes
trace_idStringTrace ID linking the redemption to the original checkout session.Sometimes

redemption_outcome values:

  • alias: The redeeming App User ID was aliased to the original web purchaser.
  • transfer: The purchase was transferred to the redeemer. A TRANSFER event is also sent.
  • redeemer_owns: The redeemer already owned the purchase. No alias or transfer occurred.

PURCHASE_REDEEMED only fires for successful redemptions. Expired or invalid tokens do not generate a webhook.

Applicable events: Price increase consent.

Uses Subscriber identity fields. Does not use the full subscription lifecycle field group.

FieldTypeDescriptionIncluded
product_idStringProduct identifier of the subscription.Always
transaction_idStringTransaction identifier.Always
original_transaction_idStringOriginal subscription transaction identifier.Always
storeStringStore of the subscription.Sometimes
environmentStringStore environment.Sometimes
currencyStringISO 4217 currency code of the new price.Sometimes
country_codeStringISO 3166-1 Alpha-2 country code.Sometimes
subscriber_attributesMapSubscriber attributes.Sometimes

Cancellation and Expiration Reasons

ReasonDescriptionApp StoreGoogle PlayAmazonWebPromo
UNSUBSCRIBESubscriber canceled 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 canceled the subscription.
PRICE_INCREASESubscriber did not agree to a price increase.
CUSTOMER_SUPPORTCustomer received a refund from Apple support, a Google Play subscription was refunded through RevenueCat, an Amazon subscription was refunded through Amazon support, or a web (RevenueCat Billing or Stripe Billing) subscription was refunded. Note that this doesn't mean that a subscription's autorenewal preference has been deactivated since refunds can be given without canceling a subscription. Check the current subscription status to see whether the subscription is still active.
UNKNOWNApple did not provide the reason for the cancellation.
SUBSCRIPTION_PAUSEDThe subscription expired because it was paused (only EXPIRATION event).
Was this page helpful?