VoidhashDocs
DevelopersHelp centerGuidesAPI reference
Dashboard
Guides
Launch
Go-live checklist
Make your first App Store purchase
Make your first Google Play purchase
Troubleshoot
Troubleshooting
Recover from incidents
SDK error codes
Purchase error codes
API error codes
FAQ
Recipes
Win back subscribers
Handle plan changes
Unlock the app after a web purchase
Link accounts across platforms
Handle refunds
Register devices for push
Migrate
Migrate to Voidhash
Migrate from RevenueCat
Migrate from Adapty
Migrate from Superwall
Run in observer mode
Privacy and hosting
Delete personal data
Self-hosting
Operate a self-hosted server

Recover from incidents

Confirm, fix and verify production failures in stores, webhooks, paywalls and keys.

This page covers failures after launch that stop purchases, renewals or events from reaching Voidhash or your backend. Each section lists the symptoms, how to confirm the cause, the fix, and how to check that it worked. For integration problems, see Troubleshooting.

Voidhash doesn't poll Apple or Google on a schedule. It learns about renewals, cancellations and refunds from store notifications, and about new purchases from your app. A subscription with no renewal keeps its access for 24 hours after its paid period, or its billing grace period, ends. Then access ends until a notification or the app reports the renewal.

To see when each store last reached Voidhash, run this VoidQL query. A store that is missing, or whose latest time is old, has stopped sending:

SELECT store, max(received_at) AS last_received, countIf(result = 'failed') AS failed
FROM store_notifications
WHERE received_at > addDays(now(), -7)
GROUP BY store

Analytics → Data health also charts the Store notification delay; see Check your data.

App Store keys revoked

Voidhash uses two Apple keys. The In-App Purchase key verifies the transactions your app reports and signs promotional offers. The App Store Connect API key only imports your products.

Symptoms

  • New App Store purchases don't unlock access. The SDK's purchase report fails with 500 (Api/SdkServiceError). Renewals and refunds from server notifications keep working.
  • Promotional offers fail at purchase. Voidhash still signs them with the stored key, but Apple refuses a revoked one.
  • Import products shows "Couldn't load this catalog" for the App Store. This is the App Store Connect API key.

Confirm. In App Store Connect, open Users and Access → Integrations and look for the Key IDs from Studio's In-app purchase key and App Store Connect API tabs. voidhash provider test app-store checks only the App Store Connect API key.

Fix. Create a key (In-App Purchase key, App Store Connect API key (Help center)), upload it on its tab, and select Save changes. From the CLI, run voidhash provider connect app-store --iap-key SubscriptionKey_ABC123DEF4.p8; settings you don't pass keep their saved values.

Verify. Make a sandbox purchase and check that the person holds the perk in People. The SDK keeps reports that failed and sends them again while the app runs, so most purchases made during the outage apply without action.

Store notifications stopped

Symptoms. Renewals, cancellations and refunds don't change access. Subscribers lose access a day after their period ends, even though they renewed. The query above shows no recent rows for the store.

Confirm.

  • App Store. In App Store Connect, open General → App Information → App Store Server Notifications. Both URLs must equal the Apple Server Notification URL in Studio and use Version 2. Deleting and re-adding the provider in Studio changes the URL; the old one answers 404.
  • Google Play. Open the Pub/Sub subscription's push metrics in Google Cloud. 401 and 503 mean the push setup is wrong; see the RTDN troubleshooting table (Help center). 500 means Voidhash couldn't read the purchase from Google; see the next section.

Fix. Correct the URL or the push subscription: Apple Server Notifications, Google Play RTDN (Help center).

What you get back. A store that received an error resends the notification on its own schedule: Pub/Sub keeps redelivering until Voidhash acknowledges it or the subscription's retention period ends. Notifications sent to a wrong URL are lost to Voidhash. Their changes return when the person's next notification arrives or when the app reports the purchase again, for example on restore. On iOS the SDK also reports renewals StoreKit delivers while the app runs.

Verify. Make a sandbox purchase, which renews within minutes, and check that the query shows new rows. On Google Play, select Send Test Message in Play Console and check that unacknowledged messages stay near zero.

Google Play service account lost access

Symptoms. New Android purchases don't unlock access, and the SDK's report fails with 500. Pub/Sub push metrics show 500 responses, and unacknowledged messages pile up. Voidhash reads every purchase and notification from the Google Play Developer API, so both stop together.

Confirm. In Play Console, open Users and permissions and check the service account still has your app with View financial data, orders, and cancellation survey responses and Manage orders and subscriptions. In Google Cloud, check that the key you uploaded still exists. voidhash provider test google-play only reads your catalog, so it can pass while purchases fail.

Fix. Grant the permissions again, or create a key and upload it on the Service account tab (Service account key (Help center)), or run voidhash provider connect google-play --service-account-key key.json. If you switch to another service account, also change the push subscription's authentication to it, because Voidhash only accepts pushes signed as the uploaded account.

Verify. Unacknowledged messages drain on their own. Then buy from a Play test track and check the person in People.

Stripe events rejected

Symptoms. Stripe purchases and renewals don't change access. In the Stripe Dashboard, your event destination shows failed deliveries.

Confirm. Open Developers → Webhooks in Stripe and check the responses:

ResponseCause
400The signing secret in Voidhash doesn't match the destination, for example after a roll.
404The URL names a Stripe provider that no longer exists.
500Voidhash couldn't read the object from Stripe, such as with a revoked API key.

A destination Stripe disabled after repeated failures shows as disabled there. voidhash provider test stripe checks the API keys, not the signing secret.

Fix. Copy the destination's signing secret into Live webhook signing secret or Test webhook signing secret and select Save changes, or run voidhash provider connect stripe --live-webhook-secret whsec_.... Re-enable a disabled destination in Stripe.

What you get back. Stripe retries failed events for a few days. For anything older, run Import history → Import again or voidhash provider import stripe --environment production. It skips what is already recorded, and imported purchases don't send your project's webhooks. See Import your Stripe history (Help center).

Verify. New deliveries in Stripe answer 2xx. Then make a test mode purchase.

Your webhook endpoint is failing

Symptoms. Your backend misses events. The endpoint shows Failed in Settings → Webhooks, or its deliveries are failed or exhausted.

Confirm. Open the endpoint's Recent deliveries to see each attempt's status code, error and response body, or run voidhash webhook deliveries <webhook> --failed.

Voidhash tries each delivery 5 times: at once, then 5 minutes, 30 minutes, 2 hours and 24 hours after the previous attempt. After 20 failed attempts in a row across its deliveries, the endpoint is set to Failed. Events that happen while an endpoint is Failed or Disabled aren't recorded for it, so they can't be sent later.

Fix.

  1. Fix your server, and its secret if you rotated it.
  2. Turn the endpoint on: Edit, then switch Enabled on, or run voidhash webhook enable. Deliveries that were waiting for a retry resume within about 20 minutes.
  3. Send the deliveries that gave up again: open each and select Retry, or run voidhash webhook retry, which offers the failed ones to choose from in a terminal. Through the API, use Retry a delivery.

Events from while the endpoint was off are gone, so resync from the API. Find who changed in that time with VoidQL, setting the window to cover the outage:

SELECT person_id FROM subscription_history
WHERE environment = 'production' AND valid_from > addDays(now(), -3)
UNION DISTINCT
SELECT person_id FROM purchases
WHERE environment = 'production'
  AND (purchased_at > addDays(now(), -3) OR refunded_at > addDays(now(), -3))

For each person, read their perks (GET …/persons/{personId}/entitlements) and, if you store them, their subscriptions, and overwrite your records with what they return.

Verify. voidhash webhook test <webhook> sends a signed test.ping and prints your answer.

A paywall deploy went wrong

Symptoms. People see a broken or unintended paywall after a deploy.

Fix. In the designer, open Builds and select Roll back on the previous build, or run voidhash paywall deploy <paywall> --build <number>. Every location showing the paywall switches right away. See Roll back.

Verify. Apps keep the paywall they loaded for up to an hour, so most people see the rollback within an hour.

A key or secret leaked

  • Secret key. In Settings → API keys, select Roll key with Stop it now, deploy the new key, and check voidhash audit for changes you didn't make. See Manage a secret key.
  • Publishable key. It ships in your app and can't be rolled. It can only act for one person on the SDK endpoints.
  • Webhook signing secret. Rotate it; see Rotate the secret.
  • Store credentials. Revoke the key at Apple, Google or Stripe, then upload a new one as above.

Next steps

  • Troubleshooting
  • Webhook delivery
  • Go-live checklist

Something wrong or missing on this page? Tell us by email or on Discord.

PreviousTroubleshootingNextSDK error codes

On this page

App Store keys revokedStore notifications stoppedGoogle Play service account lost accessStripe events rejectedYour webhook endpoint is failingA paywall deploy went wrongA key or secret leakedNext steps