This website uses cookies to ensure you get the best experience
OK
API reference
Conventions. All Task-returning members are awaited on the Unity main thread, and all callbacks and events are raised there. Every productId parameter accepts a game-side product id or a catalog sku. Amounts are in minor units — the smallest whole denomination of the currency (kopecks for RUB, like cents for USD), so 199 ₽ is 19900; Price is the same amount as a decimal (AmountMinorUnits / 100m).
IBestBridgePaymentsService
Implemented by BestBridgePaymentsService.
Properties

Member

Description

bool IsInitialized

true after Initialize() succeeded. Set before the first state and subscriptions sync completes, so it does not mean the caches are filled.

string UserId

Public player id: stable across launches, persisted locally, refreshed on every state sync. Empty until the first successful sync. Show it in-game for support lookups.

IBestBridgeMessages Messages

The active player-facing texts: the instance passed at construction, or BestBridgeMessagesDefaults.

IReadOnlyList<BestBridgeProduct> PendingSubscriptionRenewals

Products whose renewal charge is pending (subscription status Grace).

Events

Member

Raised

event Action<BestBridgeInitializationStatus> OnInitialized

Once per Initialize() call, on success and on failure. Subscribe before calling; for the already-initialized case read IsInitialized.

event Action OnSubscriptionsChanged

Only when the subscription picture changed: access gained or lost, or a difference in status, auto-renew, period or pending plan. Re-read GetSubscriptionState in the handler. Handler exceptions are caught and logged.

Lifecycle

Member

Description

Task<BestBridgeInitializationStatus> Initialize()

Authenticates the player, loads the catalog, syncs the purchase state. Repeated and concurrent calls share one in-flight task. 45 s budget; exceeding it reports ConnectionError. On success it hooks auto-recovery; on a connection failure it schedules background retries (5 s / 15 s / 45 s).

void Dispose()

On BestBridgePaymentsService (IDisposable). Releases the app-lifecycle hook used by auto-recovery. Needed only for a second instance, or when one is dropped while the app runs.

Purchasing

Member

Description

Task<BestBridgePurchaseResult> Purchase(string productId, Action<bool> callback = null, int quantity = 1)

Runs the checkout: confirmation popup → order → payment page in the external browser → polling → grant from the purchase state. callback receives true only on delivered success. quantity must be 1..99, and above 1 only for consumables, otherwise it throws; for a consumable it is the value preselected in the confirmation popup. Still pending after ~60 s of foreground polling → Error, and recovery delivers it once it settles. A call made while another purchase is in flight → Error (“Purchase already in progress”). A live subscription in the product’s group is refused before any order: the same plan → AlreadyPurchased, another plan → SubscriptionPlanChangeRequired.

Task RestorePurchases(bool showPopupOnResult = false)

Re-reads the purchase state and re-grants everything owned through OnPurchase.

Task<bool> TryProcessUnfinishedPurchaseAsync()

Delivers purchases that settled while the app was gone. Idempotent; true when at least one product was delivered. Runs automatically with autoRecoverPurchases (default) after init and on every foreground return; manual calls are deduplicated against automatic ones.

Catalog and prices

Member

Description

Task<IReadOnlyList<BestBridgeProductInfo>> GetProductsAsync()

Loads the catalog, seeds the price cache, returns one entry per sku. Needs no signed-in player, so it works before Initialize(). Throws on failure.

Task RefreshCatalogAsync()

The same reload; discards the list and swallows errors (logged). For shop open and anywhere prices are shown. Re-read the getters afterwards.

Task RefreshProductsAsync()

On BestBridgePaymentsService only. Like RefreshCatalogAsync(), but propagates the exception.

BestBridgeProductInfo GetProductInfo(string productId)

Synchronous cache read; default on a miss.

bool TryGetProductInfo(string productId, out BestBridgeProductInfo info)

The same, but separates a miss from a genuine zero price.

string GetLocalizedItemPrice(string productId)

Display price from the cache; "" when not cached.

bool TryFindProduct(string productId, out BestBridgeProduct product)

Resolves a registered mapping by product id or sku.

Ownership

Member

Description

bool IsNonConsumablePurchased(string productId)

Whether the player owns this non-consumable per the latest synced purchase state. Always false for consumables.

bool IsSubscriptionActive(string productId)

Whether a subscription entitlement in the purchase state grants access, independent of auto-renew.

Subscriptions

Member

Description

BestBridgeSubscriptionState GetSubscriptionState(string productId, out BestBridgeSubscriptionData data)

Joins access from the purchase state with the cached renewal metadata into one value for a subscription screen. Synchronous cache read; Unknown until the first successful sync. data is default when no live subscription is cached.

BestBridgeSubscriptionAction GetSubscriptionAction(string productId)

The same state resolved into a button: which control, whether it may be pressed, whether to show the end date, whether to warn. Group-aware: when another plan of the same subscription group is live, the offer is Switch (or Scheduled) rather than Subscribe, and CurrentPlanProductId names the live plan.

Task<bool> InvokeSubscriptionActionAsync(string productId)

Performs what GetSubscriptionAction currently offers (subscribe / unsubscribe / resume / switch plan). A disabled action is a logged no-op returning false. For a purchase, true means delivered, so paid-but-pending reports false.

Task<bool> Unsubscribe(string productId)

Turns off auto-renew; access lasts until period end, then expires. Irreversible, idempotent. false when no live subscription matches or the request failed.

Task<bool> PauseSubscription(string productId)

Schedules a pause: Paused (access removed) from the end of the current period.

Task<bool> ResumeSubscription(string productId)

Immediate charge and new period from Paused, or cancels a scheduled pause. false on a declined charge or missing card.

Task<bool> ChangeSubscriptionPlan(string currentProductId, string newProductId)

Within one subscription group — this, not a second Purchase, is how a player moves between tariffs. An upgrade applies immediately (prorated); a downgrade takes effect next period and shows up as PendingProductId until then. Refused locally (false, logged, no request) when the new product is not a registered subscription or the two are known to be in different groups. Shows no popups.

BestBridgeSubscriptionData[] GetUserSubscriptions()

Synchronous snapshot of the subscription cache.

bool TryGetSubscription(string productId, out BestBridgeSubscriptionData data)

First cached live subscription for the product; false on a miss.

Task UpdateSubscriptions()

Refreshes the subscription cache (renewal and billing metadata). Also runs on init and after a purchase or management call. Errors are swallowed and logged.

Task RefreshSubscriptionStatusAsync()

Full purchase-state sync plus a subscriptions refresh, so a change made on another device is picked up. Errors are swallowed and logged. Delivers no purchases. Raises OnSubscriptionsChanged on a change and reports a Grace renewal problem to the player.

IBestBridgePurchaseListener
Task<bool> OnPurchase(BestBridgePurchaseInfo purchase);
Delivers one purchased or restored product, awaited before the SDK commits the delivery. Called for fresh purchases, restores and recovered orders.

Return

Effect

true

The SDK records TransactionId in its ledger (persisted immediately) and commits, consuming a consumable. OnPurchase is not called again for that transaction.

false or a thrown exception

Nothing is committed. The entitlement stays in the purchase state and is retried on the next recovery sync or restore.

Rules: grant × purchase.Quantity, persist, then return true. Delivery is at-least-once, so the grant has to be idempotent by TransactionId — a reinstall, an identity change, or a crash between the true and its persistence re-delivers. Consumables are exempt, because a consumed entitlement leaves the purchase state.
BestBridgePurchaseInfo (readonly struct)

Field

Meaning

BestBridgeProduct Product

The granted product.

string TransactionId

Dedup key: grantedByOrderId for one-time products, subscriptionId (stable across renewals) for subscriptions.

int Quantity

Units to grant (multi-buy). 1 for non-consumables and subscriptions.

bool IsRestored

true for a restore, recovery or auto-restore; false for an interactive purchase. Use it only to skip celebration UI, never to decide whether to grant.

BestBridgePurchaseResult
Prefer the derived flags over Status: a status added in a later SDK version then cannot change what the game treats as a completed purchase.

Property

True when

bool IsDelivered

The reward reached the player. The only condition under which the product may be treated as owned.

bool IsSuccess

Same as IsDelivered (source compatibility).

bool IsPaidDeliveryPending

Charged, not delivered yet — do not grant.

bool IsAlreadyOwned

Already owned; nothing failed, nothing charged.

bool IsCanceledByPlayer

The player backed out.

bool IsFailure

Nothing new is owned: a request or processing error, a cancel or refund on the payment side, or a failed init. Excludes IsPaidDeliveryPending.

Other fields: BestBridgePurchaseStatus Status, int Quantity (units purchased), string ErrorText (raw diagnostic text for logs — never display it), int RewardIndex (not set by the purchase flow, always 0).
The SDK shows the message to the player; the game only reacts. With showPurchaseMessages: true (the default) the SDK itself shows a popup for every outcome that needs one. Use the result only to change game state — grant the product, redraw the shop — and do not show a second popup with the same information. Some outcomes get no popup, and none is needed there: the player closed the popup, a second Purchase call arrived while one was already running, or the product id is not registered in this build.
BestBridgePurchaseStatus
The last column is the text the SDK shows, unless showPurchaseMessages is off.

Value

Meaning

Message shown

Success

Order succeeded and the entitlement was delivered.

PurchaseSuccess

PaidDeliveryPending

Charged, not delivered yet: the follow-up state read failed, OnPurchase deferred, or the granted sku is not registered in this build. The next recovery sync delivers it.

PaymentStillProcessing

Canceled

Order ended canceled or refunded on the payment side.

PaymentNotCompleted

CanceledByUser

The confirmation or wait popup was dismissed.

Error

Request or processing error (see ErrorText), including the poll timeout.

ConnectionProblem / PurchaseError, or PaymentStillProcessing on the timeout; none for an unknown product id or a re-entrant call

NotInitialized

The service could not initialize; no order was created.

PurchaseUnavailable

NonConsumableAlreadyPurchased

A non-consumable the player already owns; no order created.

ProductAlreadyOwned

AlreadyPurchased

A live subscription on this product — any status, including cancelled, paused and grace; no order created.

SubscriptionAlreadyActive

SubscriptionPlanChangeRequired

A live subscription on another plan of the same group; no order created. One live subscription per group is a platform invariant enforced only after payment, so the order would be charged and grant nothing. Offer ChangeSubscriptionPlan instead.

SubscriptionAlreadyActive

Models
BestBridgeProduct (serializable struct)
BestBridgeProduct(string productId, string sku, BestBridgeProductType type)ProductId, Sku, Type. productId is game-side and never leaves the game; sku is the catalog id. They may be identical.
BestBridgeProductType
Consumable · NonConsumable · Subscription
BestBridgeProductInfo (struct)

Field

Meaning

string Title

Catalog title.

string LocalizedPrice

Display string. Default formatting: 0.00 ₽ for RUB and an empty currency, otherwise 0.00 <CURRENCY>. "" when the price is 0.

string Sku

Catalog sku.

BestBridgeProductType Type

From the catalog.

long AmountMinorUnits

Price in minor units: 199 ₽ is 19900.

decimal Price

AmountMinorUnits / 100.

string BillingPeriodUnit, int BillingPeriodCount, string SubscriptionGroup

Subscriptions only; null / 0 otherwise.

BestBridgeInitializationStatus (struct)
IsSuccess, IsError, IsConnectionError, IsCancelled, Exception. Factories: Success(), Error(exception), ConnectionError(), Cancelled().
A connection error sets both IsConnectionError and IsError and carries no Exception, so check IsConnectionError and IsCancelled first.
BestBridgeSubscriptionState

Value

Meaning

Unknown

Nothing synced yet. Render loading or disabled, never “Subscribe”.

NotSubscribed

No live subscription.

Active

Subscribed, auto-renew on.

CanceledUntilPeriodEnd

Auto-renew off; access until ExpirationDate, then expires. Auto-renew cannot be turned back on, and the plan is buyable again only once it has expired — until then the subscription is still live and an order would be charged without granting anything.

Paused

Paused; access removed until resumed.

Grace

A renewal charge failed and is being retried while access is kept.

BestBridgeSubscriptionActionKind
Loading (disabled) · Subscribe · Unsubscribe · Resume · Expiring (disabled; show the end date — the plan is buyable again only after it expires) · PaymentProblem (disabled; fixable only outside the game) · Switch (another plan of the group is live — offer to switch to this one; disabled while that plan is paused or cancelled) · Scheduled (disabled; a switch to this plan already takes effect at the end of the current period)
BestBridgeSubscriptionAction (readonly struct)
Kind, ProductId, IsEnabled, ShowsExpiration, HasPaymentProblem, State, Data, CurrentPlanProductId, SwitchTiming. Carries no player-facing copy: wording and localization stay with the game. Drive the control from IsEnabled, not from Kind: besides Loading / PaymentProblem / Scheduled / Expiring it is also false for a Switch the platform will not accept yet.
BestBridgeSubscriptionSwitchTiming
Unknown (not a switch, or catalog prices missing — promise nothing) · Immediate (an upgrade: applied and charged at once, minus a prorated credit for the unused remainder) · AtPeriodEnd (costs nothing now; takes over when the current period ends). Decided by price: strictly dearer is an upgrade, equal or cheaper is scheduled.
State describes the product itself, Kind what the button should offer — so for Switch / Scheduled the state reads NotSubscribed while CurrentPlanProductId names the plan the player is on and Data carries that plan’s record (its period is what the dates come from).
BestBridgeSubscriptionData (struct)
ProductId, Sku, SubscriptionId, SubscriptionGroup, Status, AutoRenew, ExpirationDate (end of the paid period), TimeToEndInSeconds (clamped to 0), NextBillingDate (null when auto-renew is off or paused), PendingProductId (scheduled downgrade, else null).
BestBridgeSubscriptionStatus
Active · Grace · Paused · Unknown. A terminal subscription never reaches the cache, so there is no canceled or expired value; anything the SDK does not recognize maps to Unknown.
Popup contracts
The game implements these with its own UI; the service decides when each is shown. A controller is mandatory — the constructor throws ArgumentNullException without one.
public interface IBestBridgePopupController
{
    Task<IBestBridgeWaitPopup>         ShowWaitPopup(bool canCancel);
    Task<IBestBridgeConfirmationPopup> ShowConfirmationPopup();
    Task<IBestBridgeInfoPopup>         ShowInfoPopup();
}

public interface IBestBridgeWaitPopup { CancellationToken CancellationToken { get; } void Close(); }

public interface IBestBridgeConfirmationPopup
{
    Task<BestBridgeConfirmationResult> RequestConfirmation(BestBridgeConfirmationRequest request);
}

public interface IBestBridgeInfoPopup
{
    void ShowRestoreResult(bool wasAnyRestored);
    void ShowSuccess(string productId);
    void ShowError(string productId, string message);   // message is resolved copy — render it
}
ShowError receives the resolved text and is the single path for every failure the SDK reports. The other two read their copy from service.Messages. The wait popup’s CancellationToken cancels order creation and polling.
BestBridgeConfirmationRequest (readonly struct)

Field

Meaning

ProductId, ProductType

What is being bought.

BestBridgeProductInfo ProductInfo

Cached per-unit price and title. May be default when the catalog has not loaded.

bool AllowQuantitySelection

true only for consumables — render the quantity selector.

int MinQuantity, MaxQuantity, InitialQuantity

1, 99 (MaxPurchaseQuantity), and the preselected value.

BestBridgeConfirmationResult (readonly struct)
Confirmed, Quantity. Factories: Canceled, Confirm(quantity). The quantity is validated, not clamped: return exactly what the player picked, and 1 when AllowQuantitySelection is false.
Texts: IBestBridgeMessages
Pass an instance as the last constructor argument, or derive from BestBridgeMessagesDefaults (all members virtual) and override a subset. BestBridgeMessages holds the static Russian defaults.

Member

Default (ru)

InfoHeader

Информация

ErrorHeader

Ошибка

PleaseWait

Пожалуйста, подождите…

ConfirmPaymentPrompt

Вам необходимо перейти на страницу оплаты.

QuantityLabel

Количество

PurchaseTotalFormat

Итого: {0} — {0} is the total (unit price × quantity)

PurchaseSuccess

Покупка выполнена успешно.

PurchasesRestored

Покупки восстановлены.

NoPurchasesToRestore

Нет покупок для восстановления.

ConnectionProblem

Проблема с подключением. Попробуйте восстановить покупку позже.

PurchaseError

Не удалось завершить покупку. Попробуйте позже.

PaymentStillProcessing

Платёж ещё обрабатывается. Покупка будет начислена автоматически после подтверждения.

PurchaseUnavailable

Покупки сейчас недоступны. Проверьте соединение и попробуйте позже.

ProductAlreadyOwned

Этот товар у вас уже есть.

PaymentNotCompleted

Оплата не была завершена.

SubscriptionRenewalProblem

Не удалось продлить подписку. Проверьте способ оплаты, иначе доступ будет отключён.

SubscriptionAlreadyActive

Подписка уже активна и продлевается автоматически. Повторная оплата не требуется.

BestBridgeConfig
new BestBridgeConfig(
    string apiKey,
    bool isDevBuild,
    IReadOnlyList<UserIdentity> identities = null,
    BestBridgeLogLevel? logLevel = null,
    bool notifySubscriptionPaymentProblems = true,
    bool autoRecoverPurchases = true,
    bool autoRetryFailedInitialization = true,
    bool showPurchaseMessages = true,
    BestBridgeEnvironment environment = BestBridgeEnvironment.Auto);

Member

Description

ApiKey

Project API key. Throws ArgumentException when null or blank.

IsDevBuild

Selects the built-in development or production environment, unless environment forces one.

Environment

The override as passed in. Auto (default) means no override.

ResolvedEnvironment

The environment actually in use — never Auto.

IsEnvironmentOverridden

true when the override contradicts IsDevBuild. Logged as a warning, which a release build does not print, so read this property to catch a leftover override.

BaseUrl

The resolved base URL. Validated as an absolute http(s) URL, else InvalidOperationException.

Identities

Stable identities for resolve-or-create. null or empty falls back to the device id.

LogLevel

Default Info in dev builds, Error in release. Honoured as passed in a development build; a release build caps it at Error and reduces every message.

ShowPurchaseMessages

Whether the SDK reports purchase outcomes to the player itself. Default true, covering every outcome that needs a message. false shows no result popup at all; the confirmation and wait popups, the opt-in restore result and the renewal notice are unaffected.

NotifySubscriptionPaymentProblems

Whether the SDK shows its own Grace error popup.

AutoRecoverPurchases

Whether the SDK runs recovery itself, after init and on every foreground return.

AutoRetryFailedInitialization

Whether a connection-failed start is retried in the background (5 s / 15 s / 45 s), off the caller’s path. Each attempt raises OnInitialized.

BestBridgeEnvironment
Which built-in environment to use, independently of the build type. Both are compiled into the SDK. The API key is per environment, so a forced environment needs the key that belongs to it.

Value

Meaning

Auto

Default. Follows isDevBuild: dev build → development, release build → production.

Development

Always development. For a QA or release-candidate build that must not touch real money.

Production

Always production. For verifying a real payment from a development build.

Constructors of BestBridgePaymentsService
// Production: builds a BestBridgeClient from the config.
new BestBridgePaymentsService(products, purchaseListener, popupController, config, messages = null);

// Testing / custom transport: takes an IBestBridgeClient; the config-derived flags become parameters.
new BestBridgePaymentsService(products, purchaseListener, popupController, client, messages = null,
    notifySubscriptionPaymentProblems = true, autoRecoverPurchases = true, autoRetryFailedInitialization = true,
    showPurchaseMessages = true);
Identity

Type

Description

UserIdentityType

DeviceId · GooglePlay · AppleId · Facebook · Custom

UserIdentity (readonly struct)

UserIdentity(UserIdentityType type, string value)Type, Value. Empty values are skipped in the request.

IIdentityProvider

UserIdentity GetIdentity(). One implementation per identity source.

DeviceIdIdentityProvider

SystemInfo.deviceUniqueIdentifier, with a persistent random per-install id where the platform has none.

IdentitiesListCreator.Create(params IIdentityProvider[])

Builds the list for BestBridgeConfig; null providers are skipped.

The identity set is hashed (SHA-256, order-independent) and the hash is persisted. A changed hash means a different user: the SDK resets its local ledger and cached access, then runs a full sync that auto-restores the new identity’s entitlements. A re-auth for the same identity resets nothing.
Utilities

Member

Description

BestBridgeStoreUtility.IsStoreInRuRegion(string currencyCode, bool forceTrueInEditor = true)

true for "RUB"; true in the Editor unless disabled.

BestBridgeStoreUtilityIAP.IsStoreInRuRegion(Product product, bool forceTrueInEditor = true)

The same, reading product.metadata.isoCurrencyCode. Assembly BestBridge.Payments.UnityIAP. A null product is non-RU outside the Editor.

BestBridgeTaskExtensions.Forget(this Task) / Forget<T>(this Task<T>)

Fire-and-forget that observes and logs faults.

BestBridgeLog
The SDK’s single logger.

Member

Description

Level

Requested verbosity (Off / Error / Warning / Info), applied from BestBridgeConfig.LogLevel when the transport is created. Capped at Error in a production build.

IsDevelopmentBuild

Set by the SDK from BestBridgeConfig.IsDevBuild. Defaults to false, so the testing constructor follows the production rules unless it is set explicitly.

ForceLogging(bool enabled)

Overrides the build type. true = full unreduced logs at Info in any build, including ids; false = complete silence.

ClearForcedLogging()

Drops the override and returns to build-driven behaviour.

IsForced / EffectiveLevel / IsRedacting

Current state, for a debug screen.

Custom transport: IBestBridgeClient
The layer the service runs on, implemented by BestBridgeClient (UnityWebRequest + JsonUtility). Game code normally never touches it; the second service constructor accepts one for tests or a custom implementation.

Member

Does

bool IsAuthenticated / string UserId

Auth state, and the public player id once known.

Task<bool> EnsureAuthenticatedAsync(ct)

Issues a token when missing or when the identity set changed. true means the identity changed, and the caller must discard player-scoped local state.

Task AuthenticateAsync(ct)

Issues a token unconditionally.

Task<CreateOrderResult> CreateOrderAsync(sku, idempotencyKey, quantity = 1, ct)

Creates an order for one catalog sku. Repeating a call with the same idempotencyKey never charges twice.

Task<OrderStatusResult> GetOrderAsync(orderId, ct)

Current status of one order.

Task<StateResult> GetStateAsync(long? knownVersion, ct)

Reads the purchase state; knownVersion asks for changes only.

Task ConsumeAsync(grantedByOrderId, ct)

Consumes a delivered consumable entitlement.

Task<IReadOnlyList<CatalogProduct>> GetProductsAsync(ct)

The product catalog with prices. Needs no signed-in player.

Task<IReadOnlyList<SubscriptionInfo>> GetSubscriptionsAsync(ct)

Renewal and billing metadata for the player’s subscriptions.

Task CancelSubscriptionAsync(subscriptionId, ct)

Turns off auto-renew.

Task PauseSubscriptionAsync(subscriptionId, ct)

Schedules a pause.

Task ResumeSubscriptionAsync(subscriptionId, ct)

Resumes a paused subscription, or cancels a scheduled pause.

Task ChangeSubscriptionPlanAsync(subscriptionId, sku, ct)

Moves the subscription to another plan in the same group.

Failure policy. 10 s per attempt. A transient failure is retried up to 3 times with a 2 s → 4 s → 6 s backoff. An auth failure re-issues the token and repeats the request once. Anything the policy cannot resolve surfaces as BestBridgeException.
Result types (readonly structs)

Type

Fields

CreateOrderResult

OrderId, Status, ConfirmationUrl, Amount (order total), Currency, Quantity

OrderStatusResult

OrderId, Status, PaidAtEpochMs, Amount, Currency, Quantity

StateResult

EntitlementVersion, UpToDate, Entitlements (null when up to date), CarriedEntitlementsArray (whether an entitlement list really arrived, which separates an authoritative empty state from an unusable answer)

EntitlementInfo

Sku, Type, Quantity, GrantedByOrderId, GrantedAtEpochMs, ExpiresAtEpochMs, SubscriptionId

CatalogProduct

Sku, Type, Title, PriceMinor, Currency, BillingPeriodUnit, BillingPeriodCount, SubscriptionGroup

SubscriptionInfo

SubscriptionId, Sku, SubscriptionGroup, Status, AutoRenew, CurrentPeriodEndEpochMs, NextBillingAtEpochMs, PendingSku

OrderStatus (enum)

Pending · Succeeded · Canceled · Refunded · Unknown

Exceptions
BestBridgeException
Thrown for a request failure the retry and re-auth policy could not resolve.

Member

Meaning

Message

Failure description. Diagnostic — not for display.

Code

Machine-readable cause: a payment-platform code such as QUANTITY_NOT_ALLOWED or QUANTITY_OUT_OF_RANGE, or one of NETWORK_ERROR / HTTP_<status> / INVALID_RESPONSE / UNEXPECTED_RESPONSE / INVALID_AUTH_RESPONSE.

Action

BestBridgeErrorAction: Retry · Reauth · Info (unknown values map to Info).

RequestId

Correlation id of the failed request (may be null). Quote it in support tickets.

UserId

Public player id reported with the error (may be null).

StatusCode

Status code of the failed request.

Thrown by the SDK

Exception

When

ArgumentNullException

popupController is null.

ArgumentException

apiKey null or blank; quantity != 1 for a non-consumable or subscription (argument or popup result).

ArgumentOutOfRangeException

quantity outside 1..99 (argument or popup result).

InvalidOperationException

The resolved BaseUrl is not a valid absolute http(s) URL.

BestBridgeException

An unresolved request failure. Only GetProductsAsync and RefreshProductsAsync propagate it; Purchase, the refresh helpers, UpdateSubscriptions, RestorePurchases and TryProcessUnfinishedPurchaseAsync catch and log it.

Every argument exception above is an integration error, not a runtime failure: a player cannot trigger one, and payment or connection failures arrive as a BestBridgePurchaseResult status instead. Purchase therefore needs no try/catch; such an exception is fixed at the call site, or in the confirmation popup that returned a bad quantity.