PlanyDocs
Services

EncoreService

plany.encore.v1.EncoreService — publisher links, Encores, transfers, offers, purchases, and the four calls a player's game makes.

Endpoint api.plany.cloud:443 · Global · Guide


Game-facing JSON https://encore.plany.cloud/v1/public/… · No credential · HTTPS API

Global: one endpoint for every region, because an Encore belongs to your account.

Two kinds of caller. A developer — through an API key or a session — links a publisher, declares an Encore, transfers its game and prices its offers. A player's game, with no credential at all, calls the four public methods, usually through their JSON equivalents. Reviews, outstanding limits and settlements are decided by Plany, and you see their effects on the resources below.

A call you lack permission for is answered NOT_FOUND, so nobody can learn which Encores exist from the difference.

accounts/{account}/distributorLinks/{distributor_link}

MethodRequest → ResponseNotes
CreateDistributorLink→ DistributorLinkThe key is checked with Steam before anything is stored, and its listings read. A rejected key, or one that owns no game, is INVALID_ARGUMENT; Steam not answering is UNAVAILABLE.
GetDistributorLink→ DistributorLinkNever carries the key; carries its fingerprint, outstanding, reserved and outstanding_limit.
ListDistributorLinks→ ListDistributorLinksResponse
UpdateDistributorLink→ DistributorLinkdisplay_name and steam.publisher_key. A new key must still own every game an Encore on the link sells (KEY_DOES_NOT_OWN_PRODUCT), and rotating clears STATE_CREDENTIAL_INVALID.
DeleteDistributorLink→ EmptyRefused with LINK_IN_USE while an Encore names the link or any purchase has been made through it.
ListSettlements→ ListSettlementsResponseWhat you have paid Plany for credit already issued.

Permissions: encore.links.create / .get / .list / .update / .delete. ListSettlements takes .get. Held by account.owner and account.billing; account.admin and account.viewer read only.

steam.sandbox is immutable: it sends every order to Steam's microtransaction sandbox, credits nothing and needs no outstanding limit. See Linking Steam.

Encores

accounts/{account}/encores/{encore}

MethodRequest → ResponseNotes
CreateEncore→ EncoreReturns at once in STATE_VERIFYING. game must be this account's own; listing must be one of the link's; funding_visibility is required with no working zero value. One Encore per app on the platform (PRODUCT_ALREADY_HAS_ENCORE).
GetEncore→ EncoreCarries encore_key, verification, project and transfer.
ListEncores→ ListEncoresResponsefilter accepts state = "NEEDS_REVIEW" (or another state) and nothing else.
UpdateEncore→ Encoredisplay_name and funding_visibility. Pass etag to refuse a stale write as ABORTED.
DeleteEncore→ EmptyRefused with ENCORE_TRANSFERRED once a transfer has been started or any purchase made.
RetryVerification→ EncoreFrom NEEDS_REVIEW or DECLINED only; otherwise NOT_RETRYABLE.
GetFunding→ FundingBalance, seven-day spend, runway, and purchases over the window.

Permissions: encore.encores.create / .get / .list / .update / .delete; RetryVerification takes .update; GetFunding takes encore.funding.get, which travels with billing visibility rather than with the game.

The verification policy is two outcomes, never three: VERIFIED when the linked key owns the app and the store no longer sells it or your own Steam announcement says it is ending; NEEDS_REVIEW otherwise. See Verification.

Transfers

MethodRequest → ResponseNotes
PlanTransfer→ TransferPlanChanges nothing. Every candidate in source_project, in every region, with belongs_to_game, client_facing and movable; a recommended_mode, an explanation and the warnings. Anything that cannot be listed makes the plan recommend MOVE.
StartTransfer→ OperationMODE_CONVERT re-plans and is refused with CANNOT_CONVERT unless the fresh plan recommends it; completes in the call. MODE_MOVE requires resources and acknowledge_warnings, and runs in the background. Metadata is the Transfer; the response is the Encore. Idempotent on request_id.
AcknowledgeTransferItem→ EncoreAccepts moving one item — a stopped server whose disk cannot be copied — as a fresh install. NOT_AWAITING_ACKNOWLEDGEMENT for anything else.

Permissions: encore.transfers.start on the Encore, and project.projects.update on the source project. Not implied by encore.encores.update: a transfer is a one-way decision about infrastructure. Held by account.owner and account.admin, deliberately not by account.billing. See Transferring.

Refusals: ALREADY_TRANSFERRED, TRANSFER_RUNNING, WARNINGS_NOT_ACKNOWLEDGED.

Offers

accounts/{account}/encores/{encore}/offers/{offer}

MethodRequest → ResponseNotes
CreateOffer→ Offerprice is USD in whole cents. credit is USD and at most the price less the storefront's share. display_name is what the overlay shows.
GetOffer / ListOffers→
UpdateOffer→ Offerdisplay_name, description, price, credit, active. A price change applies to purchases begun afterwards.
DeleteOffer→ EmptyAn offer somebody bought is deactivated instead.

Permissions: encore.offers.create / .get / .list / .update / .delete.

Purchases

accounts/{account}/encores/{encore}/purchases/{purchase}

MethodRequest → ResponseNotes
GetPurchase→ Purchase
ListPurchases→ ListPurchasesResponseNewest first.

There is no create: a purchase is made by a player's game. Permissions: encore.purchases.get / .list. See Offers and purchases.

Anonymous: a player's game

No credential. Named by encore_key; a purchase is proven by a Steam Web API ticket checked with the studio's own key. Each is also served as HTTPS/JSON at https://encore.plany.cloud, which is what the SDKs use.

MethodJSONNotes
GetPublicFundingPOST /v1/public/funding:getShaped by funding_visibility. Names no account.
ListPublicOffersPOST /v1/public/offers:listActive offers, even before verification, with purchasable false.
BeginPurchasePOST /v1/public/purchases:beginOpens the Steam order. Refused before Steam is called when the Encore is not verified or transferred, the offer is inactive, or the outstanding limit would be exceeded. Idempotent on request_id for the same player.
CompletePurchasePOST /v1/public/purchases:completeSettles. Safe to repeat or to skip; a decline is confirmed with Steam.

The price, the credit and the project are never taken from the request. Named refusals carry a google.rpc.ErrorInfo reason: ENCORE_NOT_VERIFIED, ENCORE_NOT_READY, OFFER_INACTIVE, PUBLISHER_LIMIT_REACHED, PUBLISHER_UNAVAILABLE, ORDER_REFUSED, PLAYER_NOT_AUTHENTICATED. See Refusals.

plany.billing.v1.BillingService/CreateCheckoutSession takes an optional project, which buys credit for a top-up-only project rather than for the account — how you fund an Encore project yourself. A player's purchase appears in ListLedgerEntries as a TYPE_PLAYER_TOP_UP entry. See Funding.