---
title: "What does the App Store notification GRACE_PERIOD_EXPIRED mean?"
description: "GRACE_PERIOD_EXPIRED means the billing grace period ended without a renewal, so turn access off. The App Store keeps retrying billing for up to 60 days."
url: https://revenuedot.app/docs/notifications/apple-grace-period-expired
---

# What does the App Store notification GRACE_PERIOD_EXPIRED mean?

The App Store notification GRACE_PERIOD_EXPIRED means the billing grace period ended before the subscription renewed.

## Quick facts

| | |
|---|---|
| Notification | `notificationType` `GRACE_PERIOD_EXPIRED` |
| Where | App Store Server Notifications v2 (`responseBodyV2DecodedPayload`) |
| Sent by | The App Store server, to your notification URL |
| What Apple says | The billing grace period ended without renewing the subscription, so you can turn off access to the service or content. |

## What triggers it

- A renewal failed, Billing Grace Period was on, and the customer did not fix their billing before the grace period ended.
- Apple says grace periods last 3 or 6 days for weekly subscriptions and 3, 16 or 28 days for monthly and longer ones, and cannot be changed once assigned.
- The subscription is still in billing retry. Apple continues for 60 days, until the customer fixes billing or cancels.

## 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. Turn off access now, and keep a message that asks the customer to update their payment method.
3. Keep listening: a later `DID_RENEW` with subtype `BILLING_RECOVERY` means billing recovered, and `EXPIRED` with `BILLING_RETRY` means Apple gave up.
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":"GRACE_PERIOD_EXPIRED","data":{"environment":"Sandbox","bundleId":"com.example.app"}};

function decide(n) {
  if (n.notificationType !== "GRACE_PERIOD_EXPIRED") return "ignore";
  return "turn off access, keep asking for a new payment method";
}

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

*Run-checked: `npm run check:snippets` runs this snippet with Node and compares its output with `turn off access` (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 keeps the billing issue on the stored purchase. Access ends when the grace period passes, and the scheduler then records `EXPIRATION` with `expiration_reason: BILLING_ERROR`. The notification itself adds no new event.

## Related

- [What does the App Store notification DID_FAIL_TO_RENEW mean?](https://revenuedot.app/docs/notifications/apple-did-fail-to-renew.md)
- [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 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
