Operator API

URnetwork API: Subscription

Version 2026.9.14 · 187 operations across 14 groups.Спецификация OpenAPI ↗

URnetwork полностью реализует спецификацию оператора протокола UR. Протокол UR ↗

Subscription

11 operations
GET/subscription/balanceBearer authsubscriptionBalance

Get the current subscription status and transfer balance. This is also the PLAN response of the onboarding program: it carries the caller's regional price_tier, the welcome onboarding_offer (null when none was issued) and the experiments assignments per surface.

Regional pricing rule (mmm/onboarding/PLAN.md): the tier is resolved, in order, from storefront_country (the store's storefront country, sent by the Apple and Google apps), the Stripe customer's billing country when a customer exists, else the client IP as a DISPLAY ESTIMATE (price_tier.estimate: true). The store charges its own storefront's price; the Stripe tier actually charged is finalized from the card's billing country once the payment method is attached, before the trial ends. The regional price is tied to the storefront/billing country, never to a VPN exit.

storefront_country(query)
string

ISO 3166-1 alpha-2 (or alpha-3) storefront country of the app's store (StoreKit Storefront.countryCode, Play billing region).

1 status · show schema
200
start_balance_byte_count
integer

The initial data balance in bytes for the period.

balance_byte_count
integer

The current data balance in bytes.

open_transfer_byte_count
integer

Data tied up in pending contracts.

current_subscription
Subscription

ONE of the active subscriptions, or absent. Shipped clients read this through the sdk and treat it as the plan indicator, so it keeps its single-value meaning and cannot name more than one store; use subscriptions for the full set.

subscription_id
string

udid

store
string
plan
string
subscriptions
array<Subscription>

EVERY store currently billing this network, one entry per store, so a caller can offer a cancel path for each -- a user subscribed on two stores is charged by both and has to cancel in both places. Not gated on Pro: an active renewal row means a store is taking money now, which is exactly when the cancel path must be reachable.

array
subscription_id
string

udid

store
string
plan
string
active_transfer_balances
array<object>
array
balance_id
string

udid

network_id
string

udid

start_time
string
end_time
string
start_balance_byte_count
integer
net_revenue_nano_cents
integer
subsidy_net_revenue_nano_cents
integer
balance_byte_count
integer
purchase_token
string
paid
boolean

The balance carries revenue. Not the same as pro -- a data code is paid but data-only.

pro
boolean

The balance carries the Pro entitlement. A network is Pro exactly when it has an in-window balance with this set.

pending_payout_usd_nano_cents
integer
update_time
string
price_tier
PriceTier
name
string
enum: standard, regional
yearly_usd
number
monthly_usd
number
currency
string

always USD

source
string

how the country was resolved

enum: storefront, billing, ip, default
estimate
boolean

true when the tier is a display estimate (ip or default)

onboarding_offer
one of

The caller's welcome offer; null when none was issued.

one of
issued_at
string (date-time)
expires_at
string (date-time)
percent_off
integer
months_free
integer
first_year_usd
number
regular_year_usd
number
tier
string
currency
string
state
string
enum: active, redeemed, expired
apple_offer_code
string
play_offer_tag
string
stripe_coupon_id
string
redeemed_at
one of

When the offer was first redeemed; null until then.

one of
string (date-time)
null
store
one of

The store of the first redemption; null until then.

one of
string
enum: apple, play, stripe, solana
null
null
experiments
map

The caller's variant per experiment surface, keyed by surface (offer.in_app, email.sequence, offer.intro_step, offer.final_screen, offer.email, offer.account, email., cadence). Only running experiments appear. A network keeps its variant for the life of an experiment (hash(networkid, experimentid), server-side). The variant holdout on offer.in_app means: show the regular plan picker, no offer screen, do not issue the offer in-app. Stamp the surface's experiment_id/variant on offer.screen.shown.

map
experiment_id
string
variant
string

a registry variant name; holdout means show nothing

GET/subscription/detailsBearer authSubscription Details

The "Manage subscription" screen: every store currently billing the caller's network, one entry per store, with the window it bought (end_time is the expiry, or the next renewal date when the store renews), the store's auto-renew state and the control that stops it.

auto_renew is true/false when the store answered and null when the store lookup failed (best-effort, ~5 s per store; the entry still carries the window from our own records). can_cancel is true only for Stripe, which /subscription/cancel acts on; Apple and Google entries carry the store's own subscriptions page in manage_url (a subscription is cancelled where it is billed); a Solana entry is a one-time USDC payment that never renews. has_stripe_customer gates the Stripe billing portal (/stripe/customer-portal errors without one).

The result is cached per network for 60 seconds; cancel and resume invalidate it.

1 status · show schema
200
subscriptions
array<object>

One entry per store billing the network, ordered by store.

array
store
string

stripe | apple | google | solana | manual | x402 | "" (unknown)

plan
string

The wire plan value ("supporter"); shown as Pro.

cadence
string

yearly | monthly | "" when unknown.

start_time
string

datetime, the start of the active window

end_time
string

datetime, the expiry or the next renewal date

auto_renew
booleannull

The store will bill again at end_time; null when the store lookup failed.

cancel_at_period_end
boolean

The store lets the paid period run out and will not bill again.

can_cancel
boolean

POST /subscription/cancel acts on this entry (Stripe only).

manage_url
string

The store's own subscriptions page (Apple, Google), else empty.

transaction_id
string

The store handle for support; invoice id, original transaction id, purchase token or payment reference.

has_stripe_customer
boolean

A Stripe customer exists for the network; gate for /stripe/customer-portal.

update_time
string

datetime

POST/subscription/cancelBearer authSubscription Cancel

Stop the Stripe subscription billing the caller's network at the end of the paid period (cancel_at_period_end); the customer keeps Pro until end_time. Only store "stripe" (the default) is acted on: the other stores answer with error.message and, for Apple/Google, the store's subscriptions page in manage_url. Idempotent: an already-cancelling subscription is not written again.

show schema
store
string

The store to act on. "stripe" (default) is the only store the server can cancel.

1 status · show schema
200
store
string
end_time
string

datetime, the end of the paid period (Pro is kept until then)

auto_renew
boolean
manage_url
string

For a store the server cannot act on, where the customer cancels.

error
object
message
string
POST/subscription/resumeBearer authSubscription Resume

Undo /subscription/cancel while the paid period is still running: the Stripe subscription renews again. Same request and result shapes.

show schema
store
string

The store to act on. "stripe" (default) is the only store the server can cancel.

1 status · show schema
200
store
string
end_time
string

datetime, the end of the paid period (Pro is kept until then)

auto_renew
boolean
manage_url
string

For a store the server cannot act on, where the customer cancels.

error
object
message
string
POST/subscription/check-balance-codeBearer authSubscription Check Balance Code

Check if the balance code is valid.

show schema
secret
string
1 status · show schema
200
balance
object
start_time
string
end_time
string
balance_byte_count
integer
error
object
message
string
POST/subscription/redeem-balance-codeBearer authSubscription Redeem Balance Code

Redeem the balance code and add the transfer balance to the caller network.

show schema
secret
string
1 status · show schema
200
transfer_balance
object
transfer_balance_id
string

udid

start_time
string
end_time
string
balance_byte_count
integer
error
object
message
string
POST/subscription/create-payment-idBearer authSubscription Create Payment Id

Creates an anonymous payment identifier to be used with purchases. This keeps network information out of the payment processor system. For example in Google Play this is called the "obfuscated account id".

show schema
empty object
1 status · show schema
200
subscription_payment_id
string

udid

error
object
message
string
POST/subscription/verify-play-purchaseBearer authSubscription Verify Play Purchase

The android app reports its purchase token BEFORE acknowledging it. The server verifies the token with the Android Publisher API and credits it through the same advisory-lock gate as the RTDN webhook and the payment reconciler, so this is idempotent against both. Because the client only acknowledges after a terminal answer, a lost webhook is no longer lost money: the store keeps redelivering the proof to the client until the server has seen it.

credited, already_credited, wrong_network and invalid are TERMINAL -- stop retrying and finalize with the store. pending is retryable (the purchase is on hold, paused or in its grace period), as is any non-2xx, which is a transport or store failure and carries no status. wrong_network means the token's linked account is a different network than the session's. The credited sku is always the store's, never the client's.

Shares a per-account budget with the Apple endpoint; every attempt counts, including failures.

show schema
package_name
string

Defaults to, and must match, this app's package.

product_id
string

The sku the client believes it bought. When set it must name one of the token's line items; the credited sku is always the store's.

purchase_token
string
3 statuses · show schema
200
status
string

credited, already_credited, wrong_network and invalid are terminal -- stop retrying and finalize with the store. pending is retryable.

enum: credited, already_credited, pending, invalid, wrong_network
expiry_time
string (date-time)

The credited window's end, when the store reported one.

401
No body
429
No body
POST/subscription/verify-apple-transactionBearer authSubscription Verify Apple Transaction

The Apple app reports its StoreKit transaction JWS (Transaction.jwsRepresentation) BEFORE calling finish(). A client report is an unauthenticated-content push, so the JWS goes through the FULL pinned-root webhook verifier -- ES256, a three-certificate x5c chain carrying Apple's policy extensions, terminating at a pinned Apple root, with the chain judged at the JWS's own signedDate -- and the bundle and environment must match this app. The signed-date freshness window is deliberately NOT applied, because a report may legitimately be retried days after the purchase; that is the whole point of the retryable reporting path.

The verified claims then credit through the same transaction ledger gate as the notification webhook and the reconciler. Statuses are the same as the Play endpoint: a JWS that fails verification is terminal invalid, never an error, so the client stops retrying.

Cheap validation runs first, then the shared per-account budget, then the cryptographic verification -- so a malformed request burns no budget and an over-budget caller burns no CPU.

show schema
signed_transaction
string

The StoreKit transaction JWS (Transaction.jwsRepresentation).

3 statuses · show schema
200
status
string

credited, already_credited, wrong_network and invalid are terminal -- stop retrying and finalize with the store. pending is retryable.

enum: credited, already_credited, pending, invalid, wrong_network
expiry_time
string (date-time)

The credited window's end, when the store reported one.

401
No body
429
No body
POST/subscription/stripe/payment-sheetBearer authstripePaymentSheet

Prepare an inline Stripe PaymentSheet purchase of Pro (the non-Play Android flavors, Windows and Linux; never the play flavor or iOS/macOS). The server creates or reuses the Stripe customer (metadata network_id) and the subscription at the caller's regional tier price: the yearly plan with the 14-day trial and, when the caller's welcome offer is redeemable, the 25% coupon applied server-side; the monthly plan without a trial. The sheet confirms the returned intent: a SetupIntent for the yearly plan (intent_type: setup, setup_intent_client_secret) or the first invoice's PaymentIntent for the monthly plan (intent_type: payment, payment_intent_client_secret). Configure the sheet with customer_id, ephemeral_key_secret and publishable_key; pass the Stripe API version the mobile SDK requires as stripe_version.

The trial is credited only once the card is attached (setup_intent.succeeded); an abandoned sheet leaves nothing behind. The charged tier is finalized from the card's billing country before the trial ends and the tier is recorded on the subscription. Calling again replaces a pending, unfinished sheet.

show schema
plan
OfferPlan
string
enum: yearly, monthly
storefront_country
string
stripe_version
string

the Stripe API version the mobile SDK requires for its ephemeral key

3 statuses · show schema
200
customer_id
string
ephemeral_key_secret
string
setup_intent_client_secret
string

set for intent_type setup (the yearly plan with its trial)

payment_intent_client_secret
string

set for intent_type payment (the monthly plan, no trial)

intent_type
string
enum: setup, payment
subscription_id
string
publishable_key
string
tier
string
currency
string
plan
string
amount_first_period_usd
number

the first period's price, with the welcome offer applied when eligible

regular_period_usd
number
trial_days
integer
trial_end_at
string (date-time)
offer_applied
boolean
error
one of
one of
message
string
null
401
No body
429
string
GET/subscription/stripe/pricesBearer authstripePrices

The Stripe price ids (and USD amounts) of the caller's regional tier, the publishable key, and the welcome-offer coupon id when the caller's offer is redeemable -- for clients that build their own Stripe flow (the Windows/Linux Payment Element).

storefront_country(query)
string

ISO 3166-1 alpha-2 storefront country, when the app knows it.

2 statuses · show schema
200
tier
string
currency
string
yearly_price_id
string
monthly_price_id
string
yearly_usd
number
monthly_usd
number
publishable_key
string
onboarding_coupon_id
string

the welcome-offer coupon, when the caller's offer is redeemable (yearly only)

offer_eligible
boolean
error
one of
one of
message
string
null
401
No body