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 storeAnalytics → 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.
401and503mean the push setup is wrong; see the RTDN troubleshooting table (Help center).500means 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:
| Response | Cause |
|---|---|
400 | The signing secret in Voidhash doesn't match the destination, for example after a roll. |
404 | The URL names a Stripe provider that no longer exists. |
500 | Voidhash 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.
- Fix your server, and its secret if you rotated it.
- 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. - 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 auditfor 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
Something wrong or missing on this page? Tell us by email or on Discord.