RefundHalt

Notification forwarding

Apple allows one notification URL. Forwarding means you never have to choose — RefundHalt relays every notification, raw and untouched, to everything else you use.

The one-URL problem

App Store Connect accepts exactly one App Store Server Notifications URL per app (one production, one sandbox). If that URL already points at your backend, RevenueCat, Adapty, or Apphud, pointing it at RefundHalt would cut them off — and vice versa.

Forwarding removes the choice. There are two directions, and both are fully supported:

Point App Store Connect at RefundHalt, then add every other consumer as a forward URL in the dashboard (your app → App Store Server Notifications → Notification forwarding):

Apple ──▶ RefundHalt ──▶ your backend
                    ├──▶ RevenueCat (its inbound Apple webhook URL)
                    └──▶ Adapty     (its inbound Apple webhook URL)

Why this direction is safer: a refund request that RefundHalt never receives cannot be answered, and Apple's 12-hour window doesn't wait. When RefundHalt is first, your refund protection never depends on a third party's forwarding reliability — and every downstream delivery is retried by us.

What exactly gets forwarded

  • Apple: the exact JSON Apple sent — {"signedPayload": "…"}. The JWS signature lives inside that string, so your destination can verify it against Apple's certificate chain exactly as if Apple had called it directly. We could not tamper with it even if we wanted to.
  • Google: the decoded RTDN JSON (the data payload of the Pub/Sub push message).

Each delivery is an HTTPS POST with these headers:

HeaderValue
Content-Typeapplication/json
User-AgentRefundHalt-Forwarder/1.0
X-RefundHalt-Forwardedtrue
X-RefundHalt-Platformapple or google

Delivery guarantees

  • Respond with any 2xx and the delivery is done.
  • 5xx, 429, timeouts, and network errors are retried with exponential backoff (30s → 1m → 5m → 15m → 1h → 2h → 4h → 8h — roughly 16 hours of retries).
  • Other 4xx responses are treated as a permanent rejection of that one notification (retrying identical bytes won't change the answer).
  • Deliveries are independent per destination — one flaky URL never delays the others, and never delays your refund protection: forwarding runs in background jobs, completely off the receiving path.
  • Up to 10 forward URLs per app, HTTPS only. Per-URL delivery health (last delivery, last status, failure streak) is visible in the dashboard.

Direction 2: your platform first

Already invested in a subscription platform and want it to stay primary in App Store Connect? All three major platforms can forward raw Apple events to RefundHalt — paste your RefundHalt notification URL into:

  • RevenueCat: Projects → your app → Apple Server Notification Forwarding URL. Heads-up: developers have reported RevenueCat's forwarding occasionally dropping notifications — if a CONSUMPTION_REQUEST is dropped, that case is lost. Prefer Direction 1 where possible.
  • Adapty: App settings → iOS SDK → URL for forwarding raw Apple events.
  • Apphud: your app → App Settings → iOS → raw App Store notifications forwarding field.

The dashboard has a step-by-step visual guide for each of these, and Verify works for every path: we fire a sandbox test notification through Apple and confirm it reaches us — directly or through your forwarder.

Is this the same as webhooks?

No. Forwarding relays the store's raw notifications unchanged. Webhooks are RefundHalt's own signed events (refund_request.created, refund.declined, …) — structured JSON about what happened and what we did about it. Use forwarding to keep existing integrations alive; use webhooks to build on RefundHalt's data.

On this page