---
title: "What does the App Store notification DID_FAIL_TO_RENEW mean?"
description: "DID_FAIL_TO_RENEW means a renewal failed because of a billing issue and the subscription entered billing retry. With subtype GRACE_PERIOD keep access; otherwise stop it and ask for new billing details."
url: https://revenuedot.app/docs/notifications/apple-did-fail-to-renew
---

# What does the App Store notification DID_FAIL_TO_RENEW mean?

The App Store notification DID_FAIL_TO_RENEW means a subscription failed to renew because of a billing issue and entered the billing retry period.

## Quick facts

| | |
|---|---|
| Notification | `notificationType` `DID_FAIL_TO_RENEW` |
| Where | App Store Server Notifications v2 (`responseBodyV2DecodedPayload`) |
| Sent by | The App Store server, to your notification URL |
| What Apple says | The subscription failed to renew due to a billing issue and entered billing retry. With subtype GRACE_PERIOD, keep serving the customer; with none, you can stop. |

## What triggers it

- The customer's payment method was declined, expired or otherwise could not be charged at renewal.
- Subtype `GRACE_PERIOD`: Billing Grace Period is on for the app, so the customer keeps access while Apple retries. Apple says to continue to provide service.
- With no subtype there is no grace period, and Apple says you can stop providing the subscription service. Apple keeps retrying billing for 60 days.

## What your server should do

1. Verify the `signedPayload` with Apple's App Store Server Library (`SignedDataVerifier.verifyAndDecodeNotification`) before you act on anything in it.
2. Tell the customer there may be a problem with their billing information and link them to their payment settings.
3. With subtype `GRACE_PERIOD`, keep access until the grace period ends (the renewal info has `gracePeriodExpiresDate`); with no subtype, pause access.
4. Answer HTTP 200 (any code from 200 to 206) once you have stored the notification. Apple retries other answers five times, at 1, 12, 24, 48 and 72 hours after the previous attempt, so make your handler safe to run twice (the payload carries a `notificationUUID`).

## Example

```javascript
// Run on the decoded payload, after you verified Apple's signature.
const notification = {"notificationType":"DID_FAIL_TO_RENEW","data":{"environment":"Sandbox","bundleId":"com.example.app"}};

function decide(n) {
  if (n.notificationType !== "DID_FAIL_TO_RENEW") return "ignore";
  return n.subtype === "GRACE_PERIOD" ? "keep access, ask the customer to fix billing" : "stop access, ask the customer to fix billing";
}

console.log(decide(notification));
```

*Run-checked: `npm run check:snippets` runs this snippet with Node and compares its output with `ask the customer to fix billing` (checked 2026-10-03).*

## How RevenueDot handles it

RevenueDot verifies Apple's signature, checks the bundle ID, stores the notification and answers 200. A purchase RevenueDot has not seen is applied only when the app's **Track new purchases from server-to-server notifications** setting is on. A type override marks the stored purchase as having a billing issue. RevenueDot sends `BILLING_ISSUE` (its `grace_period_expiration_at_ms` carries the grace end when the renewal info has one) and, as RevenueCat does, a `CANCELLATION` with `cancel_reason: BILLING_ERROR`. When access finally ends, the scheduler sends `EXPIRATION` with `expiration_reason: BILLING_ERROR`.

## Related

- [What does the App Store notification DID_RENEW with subtype BILLING_RECOVERY mean?](https://revenuedot.app/docs/notifications/apple-did-renew-billing-recovery.md)
- [What does the App Store notification GRACE_PERIOD_EXPIRED mean?](https://revenuedot.app/docs/notifications/apple-grace-period-expired.md)
- [What does the App Store notification EXPIRED with subtype BILLING_RETRY mean?](https://revenuedot.app/docs/notifications/apple-expired-billing-retry.md)
- [Which webhook events does RevenueDot send?](https://revenuedot.app/docs/api/webhook-events.md)
- [Set up App Store notifications in RevenueDot](https://revenuedot.app/docs/guides/app-store.md)

## Source

- [Apple: notificationType](https://developer.apple.com/documentation/appstoreservernotifications/notificationtype)
- [Apple: Responding to App Store Server Notifications](https://developer.apple.com/documentation/appstoreservernotifications/responding-to-app-store-server-notifications)
- [Apple: app-store-server-library-node (SignedDataVerifier)](https://github.com/apple/app-store-server-library-node)
- [RevenueDot server: stores/apple/notifications.ts (how the notification is applied)](https://github.com/revenuedot/revenuedot/blob/main/apps/server/src/stores/apple/notifications.ts)
- [RevenueDot server: stores/apple/map.ts (how the transaction becomes a stored purchase)](https://github.com/revenuedot/revenuedot/blob/main/apps/server/src/stores/apple/map.ts)
- [RevenueDot core: events.ts (how a change becomes a webhook event)](https://github.com/revenuedot/revenuedot/blob/main/packages/core/src/events.ts)
- [RevenueDot server: services/tick.ts (the scheduled EXPIRATION)](https://github.com/revenuedot/revenuedot/blob/main/apps/server/src/services/tick.ts)

Checked: 2026-10-03
