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). |
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. |
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. |
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. |
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. |
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. |
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. |
Task<bool> OnPurchase(BestBridgePurchaseInfo purchase); 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. |
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. |
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. |
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 |
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. |
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. |
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
} 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. |
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 | Подписка уже активна и продлевается автоматически. Повторная оплата не требуется. |
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. |
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. |
// 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); 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. |
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. |
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. |
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. |
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 |
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. |
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. |