# App Store refunds: REFUND notifications and consumption requests > How App Store refunds reach you: REFUND, REFUND_DECLINED, REFUND_REVERSED and CONSUMPTION_REQUEST, the 12-hour consumption reply, refund history and revoking access. - Canonical page: https://obelisk.club/blog/app-store-refunds-consumption-requests - Author: Peter Zhang - Published: 2026-11-01 - Tags: storekit, in-app-purchase, app-store-server-api, subscriptions, indie Customers ask Apple for refunds, not you. Apple decides, and your server hears about it through **App Store Server Notifications V2**: **CONSUMPTION_REQUEST** when a customer asks for a refund and Apple wants your data, then **REFUND** if it's granted, **REFUND_DECLINED** if it's refused, and **REFUND_REVERSED** if a granted refund is later reversed. You can answer a consumption request with the **Send Consumption Information** endpoint, but only with the customer's consent and, per Apple, "within 12 hours". When a refund goes through, the transaction gets a **revocationDate**, and that is your signal to remove access. If you missed notifications, **Get Refund History** returns every approved refund for a customer. ## How customers ask for a refund Apple lists several ways, such as "Contacting Apple Customer Support and asking for a refund", using Apple's self-service site **reportaproblem.apple.com**, or "Asking their payment method issuer for a refund". Apps can also start a refund request inside the app with StoreKit's `beginRefundRequest` methods; the request still goes to Apple, which makes the decision. ## The notifications All of these arrive at the App Store Server Notifications V2 URL you set in App Store Connect. If nothing arrives, see [App Store Server Notifications not arriving](/blog/app-store-server-notifications-not-arriving). | notificationType | Apple's description | What to do | |---|---|---| | CONSUMPTION_REQUEST | The customer "initiated a refund request" and "the App Store is requesting that you provide consumption data." | If the customer consented, call Send Consumption Information within 12 hours. If not, don't respond. | | REFUND | "the App Store successfully refunded a transaction" for a consumable, non-consumable, auto-renewable subscription or non-renewing subscription. | Remove what the transaction gave the customer. | | REFUND_DECLINED | "the App Store declined a refund request." | Nothing to undo. | | REFUND_REVERSED | "the App Store reversed a previously granted refund due to a dispute that the customer raised." | "If your app revoked content or services as a result of the related refund, it needs to reinstate them." | | REVOKE | A purchase the customer had through Family Sharing (or from an organization) "is no longer available", including when "the purchaser receives a refund." | Remove access for that family member. | Three related details from Apple's notification list: - When a customer starts a refund from your app with the refund request API, Apple turns off auto-renew and you get **DID_CHANGE_RENEWAL_STATUS** with subtype **AUTO_RENEW_DISABLED**. - **REFUND_DECLINED** is described in Apple's use-case table as a refund "that the customer initiated in the app, using the request refund API." Apple doesn't say whether it is also sent for requests made outside the app. - For REFUND_REVERSED on an auto-renewable subscription, "the renewal date remains unchanged when the App Store reverses a refund." The notification payload is a signed JWS. To read one while debugging, paste it into the [App Store JWS decoder](/tools/app-store-jws-decoder); it runs in your browser. ## Which products get a CONSUMPTION_REQUEST Apple's pages don't fully agree here, as read on 1 November 2026. The notificationType reference describes CONSUMPTION_REQUEST for "a consumable In-App Purchase or auto-renewable subscription", and so does the consumptionRequestReason page. The Send Consumption Information page says Apple sends it "When a customer initiates a refund request for any product type (consumable, non-consumable, non-renewing subscription, or auto-renewable subscription)", and the request body page says "You can provide consumption information for any type of product". In practice, handle the notification for every product type you sell. The notification includes **consumptionRequestReason**, the customer's stated reason: | Value | Meaning | |---|---| | UNINTENDED_PURCHASE | "The customer didn't intend to make the in-app purchase." | | FULFILLMENT_ISSUE | "The customer had issues with receiving or using the in-app purchase." | | UNSATISFIED_WITH_PURCHASE | "The customer wasn't satisfied with the in-app purchase." | | LEGAL | "The customer requested a refund based on a legal reason." | | OTHER | "The customer requested a refund for other reasons." | ## Send Consumption Information `PUT https://api.storekit.apple.com/inApps/v2/transactions/consumption/{transactionId}` (sandbox: `api.storekit-sandbox.apple.com`) The `transactionId` is the one in the CONSUMPTION_REQUEST notification. Apple's rules: - **Deadline.** "Respond within 12 hours of receiving the CONSUMPTION_REQUEST notification." Apple doesn't say what happens to a late reply. - **Consent first.** "If the customer provided consent, respond by calling this API and sending the consumption data in the ConsumptionRequest to the App Store. If not, don't respond to the CONSUMPTION_REQUEST notification." Getting that consent is your job: "You, the developer, are solely responsible for obtaining valid consent". - **Not the tracking prompt.** "Don't use the App Tracking Transparency prompt to obtain consent" for this; Apple calls the two "distinct and unrelated." - **Privacy label.** If you adopt the endpoint, Apple says to answer the app privacy questions to disclose the data you collect and what it's used for. - **What it does.** "The App Store uses the consumption information you provide to inform its refund decisions." It is one factor among "a variety of factors". A successful call returns **202 Accepted**. Other responses Apple lists: 400 (invalid request), 401 (bad JWT), 404 (transaction not found), 429 (rate limit) and 500 (try again later). ### The request body (ConsumptionRequest) | Field | Required | What it holds | |---|---|---| | customerConsented | Yes | `true` if the customer agreed to share consumption data. Anything other than `true` is rejected with HTTP 400 `InvalidCustomerConsentedError`. | | deliveryStatus | Yes | `DELIVERED`, `UNDELIVERED_QUALITY_ISSUE`, `UNDELIVERED_WRONG_ITEM`, `UNDELIVERED_SERVER_OUTAGE` or `UNDELIVERED_OTHER`. | | sampleContentProvided | Yes | `true` if, before the purchase, you offered "A free sample or free trial" or "Information about the content and how it works". | | consumptionPercentage | No | How much the customer used, in milliunits: 40% is `40000`, 100% is `100000`. | | refundPreference | No | `DECLINE`, `GRANT_FULL` or `GRANT_PRORATED`. | Rules that make a request fail or change its meaning: - **Undelivered means zero.** If deliveryStatus isn't DELIVERED, consumptionPercentage must be 0, or you get HTTP 400 `UndeliveredConsumptionPercentageNonZeroError`. - **No percentage for auto-renewable subscriptions.** Sending one fails with HTTP 400 `ConsumptionPercentageAutoRenewableSubscriptionError`; Apple works out the share for subscriptions itself "based on elapsed time." - **GRANT_PRORATED** needs a consumptionPercentage "greater than 0 and less than 100000" for consumables, non-consumables and non-renewing subscriptions. `GRANT_FULL` and `DECLINE` work for all product types. - Apple's example: if a transaction has a quantity of two consumables and one was fully used, consumptionPercentage is `50000`. Apple's ConsumptionRequest page, as read on 1 November 2026, lists only these five fields. ## Get Refund History `GET https://api.storekit.apple.com/inApps/v2/refund/lookup/{anyTransactionId}` - Pass any `originalTransactionId`, `transactionId` or `appTransactionId` that belongs to the customer for your app. - It returns "App Store-approved refunds" for all product types, up to 20 per page, sorted by revocationDate. If `hasMore` is true, call again with `?revision=` and the token from the last response. - Apple says the information "is the same as the information in one or more REFUND notifications", and suggests the endpoint to "retrieve any refund notifications you may have missed, such as during a server outage." - Apple suggests keeping the revision token from the last page so a later call returns only new refunds. - An empty `signedTransactions` array means the customer has no approved refunds. Declined requests and reversed refunds aren't described as part of this response; Apple says it holds approved refunds. ## Revoking access A refunded transaction carries these fields in its signed payload (JWSTransactionDecodedPayload): - **revocationDate**: "The UNIX time, in milliseconds, that the App Store refunded the transaction or revoked it from Family Sharing." - **revocationReason**: `0` means a refund "for other reasons, for example, an accidental purchase"; `1` means "due to an actual or perceived issue within your app." - **revocationType**: `REFUND_FULL`, `REFUND_PRORATED`, `FAMILY_REVOKE` or `ASSIGNMENT_REVOKE`. - **revocationPercentage**: for a prorated refund, "The percentage, in milliunits, of the transaction that the App Store has refunded or revoked." The rule is simple: if a transaction has a revocationDate, it no longer grants what it used to. On the device, StoreKit does this for you in one place: "Products that the App Store has refunded or revoked don't appear in the current entitlements." So an app that checks `Transaction.currentEntitlements` on launch drops a refunded non-consumable or subscription without extra code. Consumables never appear there, so for coins, credits or other balances kept on your server you have to subtract them yourself when REFUND arrives. Apple also suggests telling customers in the app about any action you take because of a refund. ## What you can't control - **The decision.** Apple decides. Your consumption data and refundPreference are inputs, and "The final refund percentage may differ from the value you provide." - **How refunds are requested.** Customers can go to Apple support, reportaproblem.apple.com or their card issuer without involving you. - **Reversals.** A refund can be reversed after a customer's dispute; you then have to restore access. - **Reasons.** The only reason you get up front is consumptionRequestReason, and revocationReason after the fact. Apple's pages don't say how long it takes to decide a refund, whether you can appeal one, or whether the refunded amount comes out of your proceeds in a specific way. They also don't promise that every refund request produces a CONSUMPTION_REQUEST. ## FAQ ### Do I have to answer CONSUMPTION_REQUEST? No. Apple tells you not to respond if the customer hasn't consented. If you do answer, Apple asks for it within 12 hours. ### Can I send consumption data without consent? No. The App Store rejects any request where customerConsented isn't `true`, with HTTP 400. ### I missed some REFUND notifications. How do I catch up? Call Get Refund History with any transaction ID for that customer. Apple suggests it for notifications missed "such as during a server outage." ### How do I know a transaction was refunded on the device? It drops out of `Transaction.currentEntitlements`, and the transaction's revocationDate is set. ### Does a reversed refund need any action? Yes. If you removed access after REFUND, Apple says you need to reinstate it after REFUND_REVERSED. ## Sources All read on 1 November 2026. - [notificationType](https://developer.apple.com/documentation/appstoreservernotifications/notificationtype), App Store Server Notifications - [consumptionRequestReason](https://developer.apple.com/documentation/appstoreservernotifications/consumptionrequestreason), App Store Server Notifications - [Send Consumption Information](https://developer.apple.com/documentation/appstoreserverapi/send-consumption-information), App Store Server API - [ConsumptionRequest](https://developer.apple.com/documentation/appstoreserverapi/consumptionrequest), App Store Server API - [deliveryStatus](https://developer.apple.com/documentation/appstoreserverapi/deliverystatus), [refundPreference](https://developer.apple.com/documentation/appstoreserverapi/refundpreference), [consumptionPercentage](https://developer.apple.com/documentation/appstoreserverapi/consumptionpercentage), [sampleContentProvided](https://developer.apple.com/documentation/appstoreserverapi/samplecontentprovided), App Store Server API - [Get Refund History](https://developer.apple.com/documentation/appstoreserverapi/get-refund-history) and [RefundHistoryResponse](https://developer.apple.com/documentation/appstoreserverapi/refundhistoryresponse), App Store Server API - [JWSTransactionDecodedPayload](https://developer.apple.com/documentation/appstoreserverapi/jwstransactiondecodedpayload), [revocationDate](https://developer.apple.com/documentation/appstoreserverapi/revocationdate), [revocationReason](https://developer.apple.com/documentation/appstoreserverapi/revocationreason), [revocationType](https://developer.apple.com/documentation/appstoreserverapi/revocationtype), App Store Server API - [Handling refund notifications](https://developer.apple.com/documentation/storekit/handling-refund-notifications), StoreKit - [currentEntitlements](https://developer.apple.com/documentation/storekit/transaction/currententitlements), StoreKit *Apple's refund rules and API fields change; check the pages above for current details.*