Use this page with AI
Copy this into your coding assistant and add your request.
Read https://openiap.dev/commerce-protocol/client and https://openiap.dev/llms.txt. Follow the reading instructions, detailed reference, and linked guides relevant to my task before making changes.
Inspect my existing project and reuse its framework and conventions. Ask me for missing product decisions. Implement the requested behavior and run the applicable checks.
Show the working result, the commands and actual test results, and any remaining limitations. Keep your explanation brief.
My request: [describe what customers should be able to do]From your app
Your backend calls the Commerce Protocol; the app sends it the purchase. The OpenIAP client libraries run the purchase and hand you the store's evidence. Send that evidence to your authenticated backend, which calls a provider's verifyPurchase and decides access.
Map a purchase to evidence#
verifyPurchase takes the purchase's store (the same value as purchase.store) and one evidence member for that store:
| store | Evidence | From the client |
|---|---|---|
apple | apple.jws | purchase.purchaseToken (the JWS on iOS) |
google | google.purchaseToken | purchase.purchaseToken |
amazon | amazon.receiptId, amazon.userId, amazon.sandbox | purchase.purchaseToken, purchase.userIdAmazon, and whether the build is an App Tester build |
horizon | horizon.sku, horizon.userId | purchase.productId, and the Meta app-scoped user id from the Platform SDK (Purchase does not carry it) |
Keep the store's user identifiers separate from your own account id. Only your backend chooses the userId it binds a purchase to.
Call the provider from your backend#
The provider documents its base URL and issues the credential. A verification-role credential may ship in an app, but calling from your backend keeps the access decision there.
// On your backend, after the app posts a Google Play purchase token
const response = await fetch(`${PROVIDER_BASE_URL}/commerce/v1/purchases/verify`, {
method: 'POST',
headers: {
authorization: `Bearer ${PROVIDER_CREDENTIAL}`,
'content-type': 'application/json',
},
body: JSON.stringify({ store: 'google', google: { purchaseToken } }),
});
// A failed call is not an invalid purchase: keep it unfinished and retry later.
if (!response.ok) throw new Error(`verifyPurchase failed: ${response.status}`);
const verdict = await response.json();
// { store, isValid, state, productId?, environment? }: require isValid and the
// expected productId, then bind the purchase and read entitlements.Verification is not an access grant: bind the purchase under your ownership policy, read current entitlements, and grant durably before the app finishes the store transaction. The Call a provider guide walks through all three calls.
Without a backend#
An app with no backend may call verifyPurchase itself: the specification lets a verification-role credential ship in an app. Accept on isValid together with the store and the productId you expected; state is advisory. Binding and entitlement reads need the server role, which never ships in an app, so the app cannot link the purchase to a user or read access from the provider.
What verifyPurchaseWithProvider is#
The client API verifyPurchaseWithProvider calls IAPKit's own verification API, not the Commerce Protocol. Changing its provider name or base URL does not turn it into a generic protocol client. To use another provider, call the protocol from your backend as shown above.
The example repository's client-bridge.mjs runs on an app backend and maps Apple, Google, Amazon, and Horizon purchase fields into verification input. Run npm run demo:bridge in the example repository to check the request boundary; it does not make a live store purchase.