Request reliability and lifecycle¶
On this page
Retries¶
NetworkExecutor.Execute defaults to RetrySafety.Never. SDK reads in the built-in managers use ExecuteRead. Economy v2 purchase/subtract operations use RetrySafety.Idempotent and retain one idempotency ID across automatic retries. Legacy purchases/consumes, login, arbitrary CloudScript, analytics, and other writes are not automatically replayed.
For a custom operation, explicitly opt in only when the operation is read-only or your server deduplicates a stable operation ID. A timeout does not prove that the server rejected a write. Retrying an ambiguous grant or spend without deduplication can apply it twice.
Retries run on unscaled time, including when Time.timeScale is zero. Server Retry-After is a minimum delay and is never shortened by the local exponential-backoff cap. Retries have a configured attempt limit. SDK transport timeouts remain controlled by the SDK.
You can pass a persisted idempotencyId to PurchaseItemV2 or ConsumeItemV2 when reconciling the same operation after a screen restart. Use a new ID for a distinct purchase, and preserve the original request payload when retrying the same ID. This is separate from a real-money store receipt's transaction ID.
Completion and disposal¶
Requests finish once through HubResult<T>. Synchronous SDK initiation exceptions become local failures. Exceptions thrown by event subscribers/callbacks are logged and isolated so they cannot prevent another subscriber receiving its result. Consumers should still handle their own errors.
NetworkExecutor.CancelPending() completes pending callers with a local cancellation error and invalidates delayed retries. It cannot undo a server write that has already been committed. Ignore stale UI results when a screen closes, and reconcile important writes with your backend.
Matchmaking handles finish once on logout or shutdown, including between scheduled polls and while fetching the final match. Status callbacks are isolated from the polling loop. Cancelling during ticket creation completes the local handle immediately; a late-created ticket is cancelled only while its original session remains active. A ticket whose creation response is lost during logout may remain on the service until its configured give-up time. Finish important cloud saves before calling logout; local cancellation is not a guarantee that a save reached the server.
Call PlayFabHub.Shutdown() to release managers, timers, runner subscriptions and the static event bus. Reinitialize with the desired settings and subscribe again. Static state resets at subsystem registration for Enter Play Mode with domain reload disabled. Custom managers can implement IDisposable (or override PlayFabFeature.Dispose) to release their resources.
Analytics is disabled by default. After enabling it in settings, the game can call Analytics.SetConsent(false) to opt out and discard queued events. Events are queued and sent individually, not combined into a lower-cost API batch. Pending events are best-effort, bounded in memory, discarded across account changes, and are not durable across process termination. Never rely on an application-quit callback for guaranteed delivery.
Real-money purchases¶
ValidateReceipt supports Unity IAP's Google Play and Apple/Mac unified receipts using legacy PlayFab v1 client validation endpoints. The inventory grant belongs to the configured legacy catalog. PlayFab performs the validation remotely through these Client APIs; the built-in helpers do not require a custom CloudScript. The wrappers omit CatalogVersion, so receipt mapping uses the primary legacy catalog, independently of economy.catalogVersion. Selecting Economy v2 does not redirect these calls to v2 Redeem APIs. See receipt setup. Other stores, modern receipt formats, subscriptions, and v2 redemption need a title-specific integration.
Persist your store transaction and fulfillment state. Confirm an order only after verifying fulfillment. If a receipt was already processed, reconcile the existing entitlement/transaction using your trusted backend before confirming; do not repeatedly grant it or blindly treat any duplicate-receipt error as success. The package's receipt parser is not a durable fulfillment ledger. Test purchase, failed validation, app restart, duplicate delivery, and restored purchases in the relevant store sandbox.
PlayFab idempotent transactions
Entity token refresh¶
When auto refresh is enabled, the runtime checks the entity token every 30 seconds and refreshes within the configured lead time. Entity calls also refresh on demand. Refresh exchanges the client session ticket, so an expired entity token can recover without an editor developer secret. An expired client session requires login again. Shutdown and logout invalidate pending refresh results to protect a subsequent session.
Concurrent entity requests share one refresh. They remain registered for cancellation while waiting, and an operation cancelled during refresh never starts afterward. Disabling the periodic refresh does not disable this on-demand check.
Economy v2 purchase retries retain a snapshot of the original prices as well as the same idempotency ID. Persist your operation ID if you need recovery across application restarts.