Make and restore purchases
Build a custom purchase UI with store-backed products.
Hosted paywalls already handle purchase and restore actions. Use the APIs on this page when you build your own purchase screen.
Load products
The SDK returns the store-backed products configured in your project, with prices already formatted for the customer's storefront:
const { data: products, error, isLoading } = voidhash.useProducts();
const monthly = products.get("monthly");data is a Map keyed by the project's product slugs. monthly is null when the store does not
return that product. This commonly means the product is not available in the current sandbox
account, country, app version, or provider configuration.
Render the store-provided displayPrice:
if (!monthly) return null;
return <Text>{monthly.displayPrice}</Text>;Start a purchase
The SDK opens the native store flow, sends the transaction to Voidhash for server validation, and refreshes the current person after success — so entitlement grants update without extra work.
purchase() resolves to a better-result Result and never rejects — cancellation is an Ok
outcome, not an error:
const { purchase, error, isLoading } = voidhash.usePurchase({
onSuccess: () => {
navigation.goBack();
},
onError: (purchaseError) => {
console.warn("Purchase failed", purchaseError);
},
});
<Button
disabled={!monthly || isLoading}
title={isLoading ? "Purchasing…" : `Continue for ${monthly?.displayPrice ?? ""}`}
onPress={async () => {
if (!monthly) return;
const result = await purchase(monthly);
if (result.isOk() && result.value.status === "cancelled") {
// The customer dismissed the store sheet. Expected — no error.
}
}}
/>The Ok outcome is one of:
| Status | Meaning |
|---|---|
completed | Validated by Voidhash; the person snapshot has been refreshed. |
cancelled | The customer dismissed the native store sheet. |
pending | The purchase needs external action; access arrives once it reconciles. |
disabled | The client was created with enabled: false. |
The Err channel carries a coded VoidhashError — typically
FAILED_TO_PURCHASE, or READ_ONLY_PURCHASE_NOT_ALLOWED in observer mode.
Grant access from Voidhash state
A successful store dialog is not the entitlement check. Unlock the feature only after the refreshed person contains an active grant.
Restore purchases
Apps should expose a visible restore action. Restore reconciles store transactions with Voidhash and refreshes the current person. It does not create a second purchase:
await voidhash.client.restorePurchases();Common failure cases
- Product is missing — verify the store product mapping and the current sandbox environment.
- Purchase already in progress — disable repeated taps while a purchase is running.
- Customer cancels — handle the
cancelledoutcome as an expected result, not an app crash. - Purchase succeeds but access is absent — retry the person fetch and verify the product grants the expected perk in Studio.
- Restore finds nothing — confirm the device uses the same App Store or Google Play account as the original purchase.