PlanyDocs
API reference

BillingService

api.plany.cloud:443Global11 methods

See your balance, add credit, choose a plan and find out what is costing money. Plany is prepaid: your plan grants credit every month, running resources draw it down by the hour, and when the balance reaches zero your workloads stop and your data is kept for 90 days before it is deleted. Read the ledger, break spending down by SKU, project or label with QueryCosts, and price a workload before you create it with EstimateCost.

GetBillingAccount

Read
plany.billing.v1.BillingService/GetBillingAccount

Parameters

  • namestringRequired

Returns

BillingAccount.

grpcurl -H "authorization: Bearer $PLANY_API_KEY" \
-d '{
"name": "accounts//billing"
}' \
api.plany.cloud:443 plany.billing.v1.BillingService/GetBillingAccount
Example response
{
"name": "accounts//billing",
"plan": "plans/my-plan",
"balance": {
"currency_code": "USD",
"units": "5",
"nanos": 0
},
"pending_charges": {
"currency_code": "USD",
"units": "5",
"nanos": 0
},
"current_period": {
"start_time": "2026-10-01T00:00:00Z",
"end_time": "2026-10-04T00:00:00Z"
},
"exhaustion_policy": "EXHAUSTION_POLICY_STOP_WORKLOADS",
"auto_topup_amount": {
"currency_code": "USD",
"units": "5",
"nanos": 0
},
"auto_topup_threshold": {
"currency_code": "USD",
"units": "5",
"nanos": 0
},
"spend_cap": {
"currency_code": "USD",
"units": "5",
"nanos": 0
},
"alert_thresholds": [
{
"currency_code": "USD",
"units": "5",
"nanos": 0
}
],
"payment_method_valid": false,
"currency_code": "",
"burn_rate_per_day": {
"currency_code": "USD",
"units": "5",
"nanos": 0
},
"projected_exhaustion_time": "2026-10-04T12:00:00Z",
"purse_balances": [
{
"purse": "PURSE_GENERAL",
"balance": {
"currency_code": "USD",
"units": "5",
"nanos": 0
},
"period_spend": {
"currency_code": "USD",
"units": "5",
"nanos": 0
},
"project": "projects/"
}
],
"subscription": {
"plan": "plans/my-plan",
"state": "STATE_ACTIVE",
"current_period_end": "2026-10-04T12:00:00Z",
"cancel_at_period_end": false,
"billing_interval": "BILLING_INTERVAL_MONTHLY",
"trial_end_time": "2026-10-04T12:00:00Z"
},
"trial_available": false
}

ListPlans

Read
plany.billing.v1.BillingService/ListPlans

Parameters

  • show_unavailablebool

    Include plans no longer offered to new accounts.

Returns

ListPlansResponse.

grpcurl -H "authorization: Bearer $PLANY_API_KEY" \
api.plany.cloud:443 plany.billing.v1.BillingService/ListPlans
Example response
{
"plans": [
{
"name": "plans/my-plan",
"display_name": "My server",
"description": "",
"monthly_price": {
"currency_code": "USD",
"units": "5",
"nanos": 0
},
"included_credit": {
"currency_code": "USD",
"units": "5",
"nanos": 0
},
"credit_rolls_over": false,
"max_rollover": {
"currency_code": "USD",
"units": "5",
"nanos": 0
},
"usage_discount_basis_points": 0,
"plan_id": "my-plan",
"available": false,
"support_tier": "",
"annual_price": {
"currency_code": "USD",
"units": "5",
"nanos": 0
},
"annual_included_credit": {
"currency_code": "USD",
"units": "5",
"nanos": 0
},
"trial_days": 0
}
]
}

GetPlan

Read
plany.billing.v1.BillingService/GetPlan

Parameters

  • namestringRequired

Returns

Plan.

grpcurl -H "authorization: Bearer $PLANY_API_KEY" \
-d '{
"name": "plans/my-plan"
}' \
api.plany.cloud:443 plany.billing.v1.BillingService/GetPlan
Example response
{
"name": "plans/my-plan",
"display_name": "My server",
"description": "",
"monthly_price": {
"currency_code": "USD",
"units": "5",
"nanos": 0
},
"included_credit": {
"currency_code": "USD",
"units": "5",
"nanos": 0
},
"credit_rolls_over": false,
"max_rollover": {
"currency_code": "USD",
"units": "5",
"nanos": 0
},
"usage_discount_basis_points": 0,
"plan_id": "my-plan",
"available": false,
"support_tier": "",
"annual_price": {
"currency_code": "USD",
"units": "5",
"nanos": 0
},
"annual_included_credit": {
"currency_code": "USD",
"units": "5",
"nanos": 0
},
"trial_days": 0
}

CreateCheckoutSession

plany.billing.v1.BillingService/CreateCheckoutSession

Starts a payment in Stripe Checkout: credit, or a plan subscription.

Returns the session to show the customer. Nothing is granted by this call: credit is added when Stripe confirms the payment, exactly once however many times the confirmation arrives. A plan's monthly credit is added the same way, once per paid invoice. Use GetCheckoutSession to find out whether it has arrived.

Pro can be paid annually by setting billing_interval to BILLING_INTERVAL_ANNUAL with plan: "plans/pro"; Hobby is monthly only. An account's first subscription to Hobby starts with a 7-day free trial: the card is taken now and first charged when the trial ends.

Parameters

  • accountstringRequired
  • request_idstringRequired

    Idempotency key. A repeated request returns the same session rather than opening a second one.

  • amountMoney

    The credit to buy, before tax. Whole cents, in the account's currency. Tax is added by Checkout on top and is never credited.

    Exactly one of amount and plan.

  • projectstring

    Buy credit for one top-up project rather than for the account.

    projects/{project}, which must belong to account and be top-up only.

  • return_pathstring

    Where the console returns to once payment completes: a path on the console, beginning with a single /. Defaults to /billing. A path rather than a URL so a session can only ever return to Plany.

  • planstring

    Subscribe to a plan rather than buy credit: plans/hobby or plans/pro. Refused for an account that already has a subscription — a switch or a cancellation is the Customer Portal's.

  • billing_intervalBillingInterval

    How often the plan is paid for. Unspecified is monthly. Annual is offered only for a plan with an annual_price. Only with plan.

    BILLING_INTERVAL_MONTHLYBILLING_INTERVAL_ANNUAL

Returns

CheckoutSession.

grpcurl -H "authorization: Bearer $PLANY_API_KEY" \
-d '{
"account": "accounts/",
"request_id": "0f8fad5b-d9cb-469f-a165-70867728950e"
}' \
api.plany.cloud:443 plany.billing.v1.BillingService/CreateCheckoutSession
Example response
{
"name": "",
"client_secret": "",
"amount": {
"currency_code": "USD",
"units": "5",
"nanos": 0
},
"project": "projects/",
"state": "STATE_OPEN",
"ledger_entry": "",
"expire_time": "2026-10-04T12:00:00Z",
"plan": "",
"trial_days": 0,
"billing_interval": "BILLING_INTERVAL_MONTHLY"
}

CreateBillingPortalSession

plany.billing.v1.BillingService/CreateBillingPortalSession

Opens Stripe's Customer Portal for the account: switching between plans, cancelling, updating the card and reading past invoices. Returns a short-lived URL to send the browser to.

Parameters

  • accountstringRequired
  • return_pathstring

    Where the portal's "return" link goes: a path on the console beginning with a single /. Defaults to /billing?tab=plans.

Returns

BillingPortalSession.

grpcurl -H "authorization: Bearer $PLANY_API_KEY" \
-d '{
"account": "accounts/"
}' \
api.plany.cloud:443 plany.billing.v1.BillingService/CreateBillingPortalSession
Example response
{
"url": ""
}

GetCheckoutSession

Read
plany.billing.v1.BillingService/GetCheckoutSession

Reads a checkout session back, so a page the customer returns to can say whether the credit has landed yet.

Parameters

  • namestringRequired

    accounts/{account}/checkoutSessions/{session}.

Returns

CheckoutSession.

grpcurl -H "authorization: Bearer $PLANY_API_KEY" \
-d '{
"name": ""
}' \
api.plany.cloud:443 plany.billing.v1.BillingService/GetCheckoutSession
Example response
{
"name": "",
"client_secret": "",
"amount": {
"currency_code": "USD",
"units": "5",
"nanos": 0
},
"project": "projects/",
"state": "STATE_OPEN",
"ledger_entry": "",
"expire_time": "2026-10-04T12:00:00Z",
"plan": "",
"trial_days": 0,
"billing_interval": "BILLING_INTERVAL_MONTHLY"
}

ListLedgerEntries

Read
plany.billing.v1.BillingService/ListLedgerEntries

Parameters

  • parentstringRequired
  • page_sizeint32
  • page_tokenstring
  • filterstring

    AIP-160 filter, e.g. type = "USAGE_CHARGE" AND project = "projects/p1".

  • intervalInterval

    Restrict to entries created in this window.

Returns

ListLedgerEntriesResponse.

grpcurl -H "authorization: Bearer $PLANY_API_KEY" \
-d '{
"parent": "accounts/",
"page_size": 50
}' \
api.plany.cloud:443 plany.billing.v1.BillingService/ListLedgerEntries
Example response
{
"ledger_entries": [
{
"name": "accounts//ledgerEntries/my-ledger-entry",
"account": "accounts/",
"type": "TYPE_PLAN_GRANT",
"amount": {
"currency_code": "USD",
"units": "5",
"nanos": 0
},
"balance_after": {
"currency_code": "USD",
"units": "5",
"nanos": 0
},
"description": "",
"sku": "",
"project": "projects/",
"resource": "",
"usage_interval": {
"start_time": "2026-10-01T00:00:00Z",
"end_time": "2026-10-04T00:00:00Z"
},
"quantity_micros": "0",
"create_time": "2026-10-04T12:00:00Z",
"expire_time": "2026-10-04T12:00:00Z",
"reverses_entry": "",
"actor": "",
"idempotency_key": "",
"explanation": "",
"purse": "PURSE_GENERAL"
}
],
"next_page_token": ""
}

QueryCosts

Read
plany.billing.v1.BillingService/QueryCosts

Aggregated spend, grouped by SKU, project, service or label. Backs the cost-breakdown views.

Parameters

  • accountstringRequired
  • intervalIntervalRequired
  • Dimensions to group by, applied in order to produce nested buckets.

    GROUP_BY_SKUGROUP_BY_PROJECTGROUP_BY_SERVICEGROUP_BY_LOCATIONGROUP_BY_RESOURCEGROUP_BY_LABELGROUP_BY_DAYGROUP_BY_HOUR
  • label_keystring

    Label key to group by, when group_by contains GROUP_BY_LABEL.

  • filterstring

Returns

QueryCostsResponse.

grpcurl -H "authorization: Bearer $PLANY_API_KEY" \
-d '{
"account": "accounts/",
"interval": {
"start_time": "2026-10-01T00:00:00Z",
"end_time": "2026-10-04T00:00:00Z"
}
}' \
api.plany.cloud:443 plany.billing.v1.BillingService/QueryCosts
Example response
{
"buckets": [
{
"keys": [
""
],
"cost": {
"currency_code": "USD",
"units": "5",
"nanos": 0
},
"quantity_micros": "0",
"usage_unit": ""
}
],
"total": {
"currency_code": "USD",
"units": "5",
"nanos": 0
}
}

EstimateCost

Read
plany.billing.v1.BillingService/EstimateCost

Prices a hypothetical workload without creating it — what a server of a given size would cost per hour, for example, before you choose it.

Parameters

  • Show child attributes
    • skustringRequired
    • quantity_microsint64Required

      Quantity in millionths of the SKU's usage unit.

    • locationstring
  • accountstring

    Price as this account would be charged, applying its plan discount and remaining free allowances. Empty gives undiscounted list prices.

  • planstring

    Price as this plan would be charged, for comparing plans before committing to one.

Returns

EstimateCostResponse.

grpcurl -H "authorization: Bearer $PLANY_API_KEY" \
-d '{
"line_items": []
}' \
api.plany.cloud:443 plany.billing.v1.BillingService/EstimateCost
Example response
{
"line_items": [
{
"sku": "",
"display_name": "My server",
"quantity_micros": "0",
"usage_unit": "",
"cost": {
"currency_code": "USD",
"units": "5",
"nanos": 0
},
"free_quantity_micros": "0"
}
],
"total": {
"currency_code": "USD",
"units": "5",
"nanos": 0
},
"plan_discount": {
"currency_code": "USD",
"units": "5",
"nanos": 0
}
}

ListSkus

Read
plany.billing.v1.BillingService/ListSkus

Parameters

  • page_sizeint32
  • page_tokenstring
  • filterstring

    AIP-160 filter, e.g. service = "microvm.plany.cloud".

  • locationstring

    Return prices for this location rather than the defaults.

Returns

ListSkusResponse.

grpcurl -H "authorization: Bearer $PLANY_API_KEY" \
-d '{
"page_size": 50
}' \
api.plany.cloud:443 plany.billing.v1.BillingService/ListSkus
Example response
{
"skus": [
{
"name": "skus/my-sku",
"display_name": "My server",
"description": "",
"service": "",
"category": "",
"price": {
"pricing_type": "PRICING_TYPE_PER_HOUR",
"usage_unit": "",
"unit_price": {
"currency_code": "USD",
"units": "5",
"nanos": 0
},
"tiering_mode": "TIERING_MODE_FLAT",
"free_quantity_per_month": "0",
"minimum_billable_quantity": "0"
},
"location_prices": {
"key": {
"pricing_type": "PRICING_TYPE_PER_HOUR",
"usage_unit": "",
"unit_price": {
"currency_code": "USD",
"units": "5",
"nanos": 0
},
"tiering_mode": "TIERING_MODE_FLAT",
"free_quantity_per_month": "0",
"minimum_billable_quantity": "0"
}
},
"quota_metric": "",
"create_time": "2026-10-04T12:00:00Z",
"effective_end_time": "2026-10-04T12:00:00Z",
"public": false
}
],
"next_page_token": ""
}

GetSku

Read
plany.billing.v1.BillingService/GetSku

Parameters

  • namestringRequired

Returns

Sku.

grpcurl -H "authorization: Bearer $PLANY_API_KEY" \
-d '{
"name": "skus/my-sku"
}' \
api.plany.cloud:443 plany.billing.v1.BillingService/GetSku
Example response
{
"name": "skus/my-sku",
"display_name": "My server",
"description": "",
"service": "",
"category": "",
"price": {
"pricing_type": "PRICING_TYPE_PER_HOUR",
"usage_unit": "",
"unit_price": {
"currency_code": "USD",
"units": "5",
"nanos": 0
},
"tiering_mode": "TIERING_MODE_FLAT",
"tiers": [
{
"start_quantity": "0",
"unit_price": {
"currency_code": "USD",
"units": "5",
"nanos": 0
}
}
],
"free_quantity_per_month": "0",
"minimum_billable_quantity": "0"
},
"location_prices": {
"key": {
"pricing_type": "PRICING_TYPE_PER_HOUR",
"usage_unit": "",
"unit_price": {
"currency_code": "USD",
"units": "5",
"nanos": 0
},
"tiering_mode": "TIERING_MODE_FLAT",
"tiers": [
{
"start_quantity": "0",
"unit_price": {
"currency_code": "USD",
"units": "5",
"nanos": 0
}
}
],
"free_quantity_per_month": "0",
"minimum_billable_quantity": "0"
}
},
"quota_metric": "",
"create_time": "2026-10-04T12:00:00Z",
"effective_end_time": "2026-10-04T12:00:00Z",
"public": false
}

The EstimateCostRequest.LineItem object

One thing to price.

Attributes

  • skustringRequired
  • quantity_microsint64Required

    Quantity in millionths of the SKU's usage unit.

  • locationstring
EstimateCostRequest.LineItem
{
"sku": "",
"quantity_micros": "0",
"location": ""
}

The EstimateCostResponse.EstimatedLineItem object

Priced line, mirroring the request order.

Attributes

  • skustring
  • display_namestring
  • quantity_microsint64
  • usage_unitstring
  • costMoney
  • free_quantity_microsint64

    Portion covered by a free allowance rather than charged.

EstimateCostResponse.EstimatedLineItem
{
"sku": "",
"display_name": "My server",
"quantity_micros": "0",
"usage_unit": "",
"cost": {
"currency_code": "USD",
"units": "5",
"nanos": 0
},
"free_quantity_micros": "0"
}

The LedgerEntry object

accounts//ledgerEntries/{{ledger_entry}}

LedgerEntry is one immutable movement of credit. The balance is the sum of entries; nothing overwrites a balance in place, so any figure can be explained by replaying the entries that produced it.

Attributes

  • namestringIdentifier
  • accountstringOutput only
  • typeLedgerEntry.TypeOutput only
    TYPE_PLAN_GRANTTYPE_PURCHASETYPE_PROMOTIONAL_GRANTTYPE_USAGE_CHARGETYPE_REFUNDTYPE_ADJUSTMENTTYPE_EXPIRYTYPE_REVERSALTYPE_PLAYER_TOP_UP
  • amountMoneyOutput only

    Signed: positive adds credit, negative spends it.

  • balance_afterMoneyOutput only

    Balance immediately after this entry, so a statement line needs no running total computed client-side.

  • descriptionstringOutput only
  • skustringOutput only

    For a USAGE_CHARGE, what it paid for.

  • projectstringOutput only
  • resourcestringOutput only
  • usage_intervalIntervalOutput only
  • quantity_microsint64Output only
  • create_timeTimestampOutput only
  • expire_timeTimestampOutput only

    When a grant's unspent remainder expires. Grants are consumed expiry-soonest first, so plan credit is spent before purchased credit.

  • reverses_entrystringOutput only

    Entry this reverses, for REVERSAL and REFUND.

  • actorstringOutput only

    Principal responsible, for ADJUSTMENT and PURCHASE.

  • idempotency_keystringOutput only

    The key that produced this entry. Unique per account, so the same usage is never charged twice.

  • explanationstringOutput only

    How the charge was arrived at, in words.

    The rating engine writes it — "4 vCPU-hours at $0.0100, less 5% Pro discount" — precisely so that support can answer "why is this line what it is" without re-running the engine against prices that may since have changed. It was stored from the start and had nowhere to go: without this field the column is write-only, and the question it exists to answer can only be answered from psql.

    Empty on entries with nothing to derive, such as a plan grant.

  • pursePurseOutput only

    Which balance this entry moved.

    Load-bearing for balance_after, which is denormalised so a statement line needs no running total computed client-side — and which now means "the balance of this entry's purse" rather than "the balance". A statement rendering two purses interleaved without reading this shows a balance that appears to jump back and forth, which reads as a bug in the ledger.

    Unset means the general purse, and every entry written before purses existed is one.

    PURSE_GENERALPURSE_PROJECT
LedgerEntry
{
"name": "accounts//ledgerEntries/my-ledger-entry",
"account": "accounts/",
"type": "TYPE_PLAN_GRANT",
"amount": {
"currency_code": "USD",
"units": "5",
"nanos": 0
},
"balance_after": {
"currency_code": "USD",
"units": "5",
"nanos": 0
},
"description": "",
"sku": "",
"project": "projects/",
"resource": "",
"usage_interval": {
"start_time": "2026-10-01T00:00:00Z",
"end_time": "2026-10-04T00:00:00Z"
},
"quantity_micros": "0",
"create_time": "2026-10-04T12:00:00Z",
"expire_time": "2026-10-04T12:00:00Z",
"reverses_entry": "",
"actor": "",
"idempotency_key": "",
"explanation": "",
"purse": "PURSE_GENERAL"
}

The PurseBalance object

PurseBalance is one of an account's credit balances.

Attributes

  • pursePurse
    PURSE_GENERALPURSE_PROJECT
  • balanceMoney

    Spendable credit in this purse. Never negative except for the tail of one in-flight workload — see Purse.

  • period_spendMoney

    Spend against this purse in the current billing period.

  • projectstring

    projects/{project}, for a PURSE_PROJECT balance. Empty otherwise.

PurseBalance
{
"purse": "PURSE_GENERAL",
"balance": {
"currency_code": "USD",
"units": "5",
"nanos": 0
},
"period_spend": {
"currency_code": "USD",
"units": "5",
"nanos": 0
},
"project": "projects/"
}

The QueryCostsResponse.CostBucket object

One bucket of aggregated spend.

Attributes

  • keysrepeated string

    Dimension values in the order requested, e.g. ["skus/playpute-vcpu-hour", "projects/p1"].

  • costMoney
  • quantity_microsint64
  • usage_unitstring
QueryCostsResponse.CostBucket
{
"keys": [
""
],
"cost": {
"currency_code": "USD",
"units": "5",
"nanos": 0
},
"quantity_micros": "0",
"usage_unit": ""
}

The Subscription object

What pays for a billing account's plan.

Attributes

  • planstring

    The plan the subscription is for.

  • STATE_ACTIVESTATE_PAST_DUESTATE_CANCELEDSTATE_INCOMPLETESTATE_TRIALING
  • current_period_endTimestamp

    When the current paid period ends, and the next renewal is due.

  • cancel_at_period_endbool

    Cancelled, and running until current_period_end.

  • billing_intervalBillingInterval

    Monthly or annual.

    BILLING_INTERVAL_MONTHLYBILLING_INTERVAL_ANNUAL
  • trial_end_timeTimestamp

    When the free trial ends, while the subscription is in one.

Subscription
{
"plan": "plans/my-plan",
"state": "STATE_ACTIVE",
"current_period_end": "2026-10-04T12:00:00Z",
"cancel_at_period_end": false,
"billing_interval": "BILLING_INTERVAL_MONTHLY",
"trial_end_time": "2026-10-04T12:00:00Z"
}

The Price object

Price is a complete, ratable price for one SKU in one currency.

Attributes

  • pricing_typePricingTypeRequired
    PRICING_TYPE_PER_HOURPRICING_TYPE_PER_UNIT_HOURPRICING_TYPE_PER_UNIT_MONTHPRICING_TYPE_PER_UNIT_ONCEPRICING_TYPE_PER_REQUESTPRICING_TYPE_PER_GIB_TRANSFERPRICING_TYPE_FLAT_MONTHLYPRICING_TYPE_FREE
  • usage_unitstringRequired

    The unit quantity is measured in, for display and for sanity-checking emitters: "vcpu-hour", "gib-hour", "gib", "request", "hour", "month".

  • unit_priceMoney

    Price per usage_unit. Ignored when tiering_mode is GRADUATED or VOLUME.

  • tiering_modeTieringMode
    TIERING_MODE_FLATTIERING_MODE_GRADUATEDTIERING_MODE_VOLUME
  • Bands, ascending by start_quantity. Only read for GRADUATED and VOLUME.

    Show child attributes
    • start_quantityint64Required

      Inclusive lower bound of this band, in the SKU's usage unit.

    • unit_priceMoneyRequired

      Price for one unit within this band. Uses google.type.Money's units/nanos, giving nine decimal places — enough for rates like $0.000011 per vCPU second without rounding drift.

  • free_quantity_per_monthint64

    Quantity granted free per account per calendar month before charging begins. This is how the free tier is expressed per-SKU rather than as a special case in the rating engine.

  • minimum_billable_quantityint64

    Smallest quantity that can be billed, in usage_unit. A VM that lives for 40 seconds against a 60-second minimum is billed for 60. Guards against create/destroy loops costing more to meter than they earn.

Price
{
"pricing_type": "PRICING_TYPE_PER_HOUR",
"usage_unit": "",
"unit_price": {
"currency_code": "USD",
"units": "5",
"nanos": 0
},
"tiering_mode": "TIERING_MODE_FLAT",
"tiers": [
{
"start_quantity": "0",
"unit_price": {
"currency_code": "USD",
"units": "5",
"nanos": 0
}
}
],
"free_quantity_per_month": "0",
"minimum_billable_quantity": "0"
}

The PricingTier object

PricingTier is one band of a graduated or volume price.

Tiers are ordered by start_quantity ascending and the first tier must start at zero. With graduated tiering, quantity within each band is charged at that band's rate; with volume tiering, the whole quantity is charged at the rate of the band it lands in.

Attributes

  • start_quantityint64Required

    Inclusive lower bound of this band, in the SKU's usage unit.

  • unit_priceMoneyRequired

    Price for one unit within this band. Uses google.type.Money's units/nanos, giving nine decimal places — enough for rates like $0.000011 per vCPU second without rounding drift.

PricingTier
{
"start_quantity": "0",
"unit_price": {
"currency_code": "USD",
"units": "5",
"nanos": 0
}
}

BillingAccount

period and spend controls.

  • namestringIdentifier

    accounts/{account}/billing.

  • planstringOutput only

    Current plan, plans/{plan}.

  • balanceMoneyOutput only

    Spendable credit. Never negative: usage that would overdraw stops the workload instead.

  • pending_chargesMoneyOutput only

    Charges accrued but not yet posted, from the current partial hour. Shown so the console's balance does not appear to jump each hour.

  • current_periodIntervalOutput only

    Current billing period, when the plan grant lands and when it expires.

  • EXHAUSTION_POLICY_STOP_WORKLOADSEXHAUSTION_POLICY_AUTO_TOPUP
  • auto_topup_amountMoney

    Amount to buy when auto top-up triggers.

  • auto_topup_thresholdMoney

    Balance at which auto top-up triggers.

  • spend_capMoney

    Hard ceiling on spend per billing period. Once reached, workloads stop even if credit remains — the guard rail that lets a studio hand a project to a contractor without unbounded exposure. Zero means no cap.

  • alert_thresholdsrepeated Money

    Balances at which to notify the account, e.g. $5 and $1. Each fires once per period.

  • payment_method_validboolOutput only

    Whether a usable payment method is on file.

  • currency_codestringOutput only

    ISO 4217 currency for this account. Fixed at creation; all Money on the account uses it.

  • burn_rate_per_dayMoneyOutput only

    Observed burn rate over the last 24 hours, used to project a runout date and to warn before the balance actually hits zero.

  • projected_exhaustion_timeTimestampOutput only

    Projected exhaustion at the current burn rate. The single most useful number to put in front of a customer.

  • purse_balancesrepeated PurseBalanceOutput only

    Every balance this account holds, including the general one.

    balance above stays the general purse and keeps meaning exactly what it always meant, because every existing caller reads it and none of them knows about purses. A console showing one number is showing the number it has always shown.

    Show child attributes
    • pursePurse
      PURSE_GENERALPURSE_PROJECT
    • balanceMoney

      Spendable credit in this purse. Never negative except for the tail of one in-flight workload — see Purse.

    • period_spendMoney

      Spend against this purse in the current billing period.

    • projectstring

      projects/{project}, for a PURSE_PROJECT balance. Empty otherwise.

  • subscriptionSubscriptionOutput only

    The Stripe subscription that pays for the plan, when one does.

    Absent for an account whose plan credit Plany grants without charging — every account opened before plans were sold, and every invited one. Present and not ACTIVE is a plan whose monthly credit has stopped: the renewal failed or the subscription ended, and purchased credit is all the account is running on.

    Show child attributes
    • planstring

      The plan the subscription is for.

    • STATE_ACTIVESTATE_PAST_DUESTATE_CANCELEDSTATE_INCOMPLETESTATE_TRIALING
    • current_period_endTimestamp

      When the current paid period ends, and the next renewal is due.

    • cancel_at_period_endbool

      Cancelled, and running until current_period_end.

    • billing_intervalBillingInterval

      Monthly or annual.

      BILLING_INTERVAL_MONTHLYBILLING_INTERVAL_ANNUAL
    • trial_end_timeTimestamp

      When the free trial ends, while the subscription is in one.

  • trial_availableboolOutput only

    Whether a subscription opened now would start with the plan's free trial. True only for an account that has never had a subscription, so a trial is had once per account.

BillingPortalSession

A Customer Portal session.

  • urlstringOutput only

    Stripe's portal page for this account. Short-lived and single-use; send the browser to it immediately rather than storing it.

CheckoutSession

A Stripe Checkout session for credit.

  • namestringOutput only

    accounts/{account}/checkoutSessions/{session}, the session id being Stripe's.

  • client_secretstringOutput only

    What mounts embedded Checkout in the browser. Present while the session is open; a session that has completed or expired has nothing to mount.

  • amountMoneyOutput only

    The credit being bought, before tax.

  • projectstringOutput only

    The top-up project the credit is for, when it is for one.

  • stateCheckoutSession.StateOutput only
    STATE_OPENSTATE_PROCESSINGSTATE_PAIDSTATE_EXPIRED
  • ledger_entrystringOutput only

    The grant this payment produced, once it has.

  • expire_timeTimestampOutput only
  • planstringOutput only

    The plan being subscribed to, for a subscription session. amount is then the plan's monthly price, and ledger_entry stays empty: a plan's credit is granted per invoice, not per session.

  • trial_daysint32Output only

    Days of free trial the subscription starts with, when it does. amount is then charged at the trial's end rather than now.

  • billing_intervalBillingIntervalOutput only

    How often the plan this session subscribes to is paid for.

    BILLING_INTERVAL_MONTHLYBILLING_INTERVAL_ANNUAL

EstimateCostResponse

  • Show child attributes
    • skustring
    • display_namestring
    • quantity_microsint64
    • usage_unitstring
    • costMoney
    • free_quantity_microsint64

      Portion covered by a free allowance rather than charged.

  • totalMoney
  • plan_discountMoney

    Discount the account's plan removed from the list price.

ListLedgerEntriesResponse

  • ledger_entriesrepeated LedgerEntry
    Show child attributes
    • namestringIdentifier
    • accountstringOutput only
    • typeLedgerEntry.TypeOutput only
      TYPE_PLAN_GRANTTYPE_PURCHASETYPE_PROMOTIONAL_GRANTTYPE_USAGE_CHARGETYPE_REFUNDTYPE_ADJUSTMENTTYPE_EXPIRYTYPE_REVERSALTYPE_PLAYER_TOP_UP
    • amountMoneyOutput only

      Signed: positive adds credit, negative spends it.

    • balance_afterMoneyOutput only

      Balance immediately after this entry, so a statement line needs no running total computed client-side.

    • descriptionstringOutput only
    • skustringOutput only

      For a USAGE_CHARGE, what it paid for.

    • projectstringOutput only
    • resourcestringOutput only
    • usage_intervalIntervalOutput only
    • quantity_microsint64Output only
    • create_timeTimestampOutput only
    • expire_timeTimestampOutput only

      When a grant's unspent remainder expires. Grants are consumed expiry-soonest first, so plan credit is spent before purchased credit.

    • reverses_entrystringOutput only

      Entry this reverses, for REVERSAL and REFUND.

    • actorstringOutput only

      Principal responsible, for ADJUSTMENT and PURCHASE.

    • idempotency_keystringOutput only

      The key that produced this entry. Unique per account, so the same usage is never charged twice.

    • explanationstringOutput only

      How the charge was arrived at, in words.

      The rating engine writes it — "4 vCPU-hours at $0.0100, less 5% Pro discount" — precisely so that support can answer "why is this line what it is" without re-running the engine against prices that may since have changed. It was stored from the start and had nowhere to go: without this field the column is write-only, and the question it exists to answer can only be answered from psql.

      Empty on entries with nothing to derive, such as a plan grant.

    • pursePurseOutput only

      Which balance this entry moved.

      Load-bearing for balance_after, which is denormalised so a statement line needs no running total computed client-side — and which now means "the balance of this entry's purse" rather than "the balance". A statement rendering two purses interleaved without reading this shows a balance that appears to jump back and forth, which reads as a bug in the ledger.

      Unset means the general purse, and every entry written before purses existed is one.

      PURSE_GENERALPURSE_PROJECT
  • next_page_tokenstring

ListPlansResponse

  • Show child attributes
    • namestringIdentifier

      plans/{plan} — plans/hobby or plans/pro.

    • display_namestringOutput only
    • descriptionstringOutput only
    • monthly_priceMoneyOutput only

      Charged monthly: $5 for Hobby, $20 for Pro.

    • included_creditMoneyOutput only

      Credit granted at the start of each billing period. Equal to monthly_price on both current plans, so the subscription fee is entirely spendable and the plan is effectively a prepaid bundle rather than a fee on top of usage.

    • credit_rolls_overboolOutput only

      Whether unspent included credit carries into the next period. False on both launch plans: included credit expires, purchased credit does not.

    • max_rolloverMoneyOutput only

      Cap on rolled-over credit, when rollover is enabled.

    • usage_discount_basis_pointsint32Output only

      Discount applied to usage rates while on this plan, in basis points (500 = 5% off). Zero on Hobby; Pro trades a higher fee for cheaper usage.

    • plan_idstringOutput only

      Plan id used as the key in QuotaMetric.plan_defaults, tying plans to the quota model without either service importing the other's storage.

    • availableboolOutput only

      Whether new accounts may select this plan. A retired plan stays readable so existing subscribers still resolve.

    • support_tierstringOutput only

      Support response target, for display on the pricing page.

    • annual_priceMoneyOutput only

      Charged once a year when the plan is paid annually. Absent for a plan that has no annual variant. $200 for Pro.

    • annual_included_creditMoneyOutput only

      Credit granted at the start of each month of an annual subscription — more than included_credit, which is part of what paying a year ahead buys. $25 for Pro. Absent when annual_price is.

    • trial_daysint32Output only

      Days of free trial an account's first subscription to this plan starts with. The trial's period is granted the plan's included_credit, expiring when the trial ends. 7 on Hobby; zero on a plan with no trial.

ListSkusResponse

  • Show child attributes
    • display_namestringRequired
    • servicestringRequired

      The product that owns this SKU, e.g. secretmanager.plany.cloud. Groups line items on a statement.

    • pricePriceRequired

      Default price, used where no location override applies.

      Show child attributes
      • pricing_typePricingTypeRequired
        PRICING_TYPE_PER_HOURPRICING_TYPE_PER_UNIT_HOURPRICING_TYPE_PER_UNIT_MONTHPRICING_TYPE_PER_UNIT_ONCEPRICING_TYPE_PER_REQUESTPRICING_TYPE_PER_GIB_TRANSFERPRICING_TYPE_FLAT_MONTHLYPRICING_TYPE_FREE
      • usage_unitstringRequired

        The unit quantity is measured in, for display and for sanity-checking emitters: "vcpu-hour", "gib-hour", "gib", "request", "hour", "month".

      • unit_priceMoney

        Price per usage_unit. Ignored when tiering_mode is GRADUATED or VOLUME.

      • tiering_modeTieringMode
        TIERING_MODE_FLATTIERING_MODE_GRADUATEDTIERING_MODE_VOLUME
      • Bands, ascending by start_quantity. Only read for GRADUATED and VOLUME.

      • free_quantity_per_monthint64

        Quantity granted free per account per calendar month before charging begins. This is how the free tier is expressed per-SKU rather than as a special case in the rating engine.

      • minimum_billable_quantityint64

        Smallest quantity that can be billed, in usage_unit. A VM that lives for 40 seconds against a 60-second minimum is billed for 60. Guards against create/destroy loops costing more to meter than they earn.

    • namestringIdentifier

      skus/{sku}, where the id is stable and readable, e.g. skus/microvm-vcpu-hour-standard.

    • descriptionstring
    • categorystring

      Coarse family for reporting: "compute", "storage", "network", "support".

    • location_pricesmap<string, Price>

      Per-location price overrides keyed by location id ("eu-west-2"). Regions genuinely cost different amounts to run, and this keeps that visible rather than averaged into one global rate.

      Show child attributes
      • pricing_typePricingTypeRequired
        PRICING_TYPE_PER_HOURPRICING_TYPE_PER_UNIT_HOURPRICING_TYPE_PER_UNIT_MONTHPRICING_TYPE_PER_UNIT_ONCEPRICING_TYPE_PER_REQUESTPRICING_TYPE_PER_GIB_TRANSFERPRICING_TYPE_FLAT_MONTHLYPRICING_TYPE_FREE
      • usage_unitstringRequired

        The unit quantity is measured in, for display and for sanity-checking emitters: "vcpu-hour", "gib-hour", "gib", "request", "hour", "month".

      • unit_priceMoney

        Price per usage_unit. Ignored when tiering_mode is GRADUATED or VOLUME.

      • tiering_modeTieringMode
        TIERING_MODE_FLATTIERING_MODE_GRADUATEDTIERING_MODE_VOLUME
      • Bands, ascending by start_quantity. Only read for GRADUATED and VOLUME.

      • free_quantity_per_monthint64

        Quantity granted free per account per calendar month before charging begins. This is how the free tier is expressed per-SKU rather than as a special case in the rating engine.

      • minimum_billable_quantityint64

        Smallest quantity that can be billed, in usage_unit. A VM that lives for 40 seconds against a 60-second minimum is billed for 60. Guards against create/destroy loops costing more to meter than they earn.

    • quota_metricstring

      Quota metric this SKU's usage also counts against, if any. Links the "how much may I have" and "what does it cost" models.

    • create_timeTimestampOutput only
    • effective_end_timeTimestamp

      When this SKU stops being ratable. Usage after this is rejected rather than silently priced at zero.

    • publicbool

      Whether the SKU is visible on the public price list. Internal SKUs cover costs Plany absorbs and are hidden.

  • next_page_tokenstring

Plan

Plan is a subscription tier. The brief defines two.

  • namestringIdentifier

    plans/{plan} — plans/hobby or plans/pro.

  • display_namestringOutput only
  • descriptionstringOutput only
  • monthly_priceMoneyOutput only

    Charged monthly: $5 for Hobby, $20 for Pro.

  • included_creditMoneyOutput only

    Credit granted at the start of each billing period. Equal to monthly_price on both current plans, so the subscription fee is entirely spendable and the plan is effectively a prepaid bundle rather than a fee on top of usage.

  • credit_rolls_overboolOutput only

    Whether unspent included credit carries into the next period. False on both launch plans: included credit expires, purchased credit does not.

  • max_rolloverMoneyOutput only

    Cap on rolled-over credit, when rollover is enabled.

  • usage_discount_basis_pointsint32Output only

    Discount applied to usage rates while on this plan, in basis points (500 = 5% off). Zero on Hobby; Pro trades a higher fee for cheaper usage.

  • plan_idstringOutput only

    Plan id used as the key in QuotaMetric.plan_defaults, tying plans to the quota model without either service importing the other's storage.

  • availableboolOutput only

    Whether new accounts may select this plan. A retired plan stays readable so existing subscribers still resolve.

  • support_tierstringOutput only

    Support response target, for display on the pricing page.

  • annual_priceMoneyOutput only

    Charged once a year when the plan is paid annually. Absent for a plan that has no annual variant. $200 for Pro.

  • annual_included_creditMoneyOutput only

    Credit granted at the start of each month of an annual subscription — more than included_credit, which is part of what paying a year ahead buys. $25 for Pro. Absent when annual_price is.

  • trial_daysint32Output only

    Days of free trial an account's first subscription to this plan starts with. The trial's period is granted the plan's included_credit, expiring when the trial ends. 7 on Hobby; zero on a plan with no trial.

QueryCostsResponse

  • Show child attributes
    • keysrepeated string

      Dimension values in the order requested, e.g. ["skus/playpute-vcpu-hour", "projects/p1"].

    • costMoney
    • quantity_microsint64
    • usage_unitstring
  • totalMoney

Sku

Sku is a priced, meterable thing. Services register their own SKUs, which is how "resources/services support per-hour billing with the ability to set their own pricing types" is delivered without billing knowing about them.

  • display_namestringRequired
  • servicestringRequired

    The product that owns this SKU, e.g. secretmanager.plany.cloud. Groups line items on a statement.

  • pricePriceRequired

    Default price, used where no location override applies.

    Show child attributes
    • pricing_typePricingTypeRequired
      PRICING_TYPE_PER_HOURPRICING_TYPE_PER_UNIT_HOURPRICING_TYPE_PER_UNIT_MONTHPRICING_TYPE_PER_UNIT_ONCEPRICING_TYPE_PER_REQUESTPRICING_TYPE_PER_GIB_TRANSFERPRICING_TYPE_FLAT_MONTHLYPRICING_TYPE_FREE
    • usage_unitstringRequired

      The unit quantity is measured in, for display and for sanity-checking emitters: "vcpu-hour", "gib-hour", "gib", "request", "hour", "month".

    • unit_priceMoney

      Price per usage_unit. Ignored when tiering_mode is GRADUATED or VOLUME.

    • tiering_modeTieringMode
      TIERING_MODE_FLATTIERING_MODE_GRADUATEDTIERING_MODE_VOLUME
    • Bands, ascending by start_quantity. Only read for GRADUATED and VOLUME.

      Show child attributes
      • start_quantityint64Required

        Inclusive lower bound of this band, in the SKU's usage unit.

      • unit_priceMoneyRequired

        Price for one unit within this band. Uses google.type.Money's units/nanos, giving nine decimal places — enough for rates like $0.000011 per vCPU second without rounding drift.

    • free_quantity_per_monthint64

      Quantity granted free per account per calendar month before charging begins. This is how the free tier is expressed per-SKU rather than as a special case in the rating engine.

    • minimum_billable_quantityint64

      Smallest quantity that can be billed, in usage_unit. A VM that lives for 40 seconds against a 60-second minimum is billed for 60. Guards against create/destroy loops costing more to meter than they earn.

  • namestringIdentifier

    skus/{sku}, where the id is stable and readable, e.g. skus/microvm-vcpu-hour-standard.

  • descriptionstring
  • categorystring

    Coarse family for reporting: "compute", "storage", "network", "support".

  • location_pricesmap<string, Price>

    Per-location price overrides keyed by location id ("eu-west-2"). Regions genuinely cost different amounts to run, and this keeps that visible rather than averaged into one global rate.

    Show child attributes
    • pricing_typePricingTypeRequired
      PRICING_TYPE_PER_HOURPRICING_TYPE_PER_UNIT_HOURPRICING_TYPE_PER_UNIT_MONTHPRICING_TYPE_PER_UNIT_ONCEPRICING_TYPE_PER_REQUESTPRICING_TYPE_PER_GIB_TRANSFERPRICING_TYPE_FLAT_MONTHLYPRICING_TYPE_FREE
    • usage_unitstringRequired

      The unit quantity is measured in, for display and for sanity-checking emitters: "vcpu-hour", "gib-hour", "gib", "request", "hour", "month".

    • unit_priceMoney

      Price per usage_unit. Ignored when tiering_mode is GRADUATED or VOLUME.

    • tiering_modeTieringMode
      TIERING_MODE_FLATTIERING_MODE_GRADUATEDTIERING_MODE_VOLUME
    • Bands, ascending by start_quantity. Only read for GRADUATED and VOLUME.

      Show child attributes
      • start_quantityint64Required

        Inclusive lower bound of this band, in the SKU's usage unit.

      • unit_priceMoneyRequired

        Price for one unit within this band. Uses google.type.Money's units/nanos, giving nine decimal places — enough for rates like $0.000011 per vCPU second without rounding drift.

    • free_quantity_per_monthint64

      Quantity granted free per account per calendar month before charging begins. This is how the free tier is expressed per-SKU rather than as a special case in the rating engine.

    • minimum_billable_quantityint64

      Smallest quantity that can be billed, in usage_unit. A VM that lives for 40 seconds against a 60-second minimum is billed for 60. Guards against create/destroy loops costing more to meter than they earn.

  • quota_metricstring

    Quota metric this SKU's usage also counts against, if any. Links the "how much may I have" and "what does it cost" models.

  • create_timeTimestampOutput only
  • effective_end_timeTimestamp

    When this SKU stops being ratable. Usage after this is rejected rather than silently priced at zero.

  • publicbool

    Whether the SKU is visible on the public price list. Internal SKUs cover costs Plany absorbs and are hidden.

Enums

BillingAccount.ExhaustionPolicy

How the account behaves as the balance nears zero.

ValueDescription
EXHAUSTION_POLICY_UNSPECIFIED
EXHAUSTION_POLICY_STOP_WORKLOADSStop workloads, keep data. The default and the only option for an account with no payment method.
EXHAUSTION_POLICY_AUTO_TOPUPCharge the payment method for a top-up and keep running. What a studio wants; requires a verified card.

BillingInterval

How often a subscription is paid for.

ValueDescription
BILLING_INTERVAL_UNSPECIFIED
BILLING_INTERVAL_MONTHLYPaid each month; each paid month grants `Plan.included_credit`.
BILLING_INTERVAL_ANNUALPaid a year ahead; each month of that year grants `Plan.annual_included_credit`.

CheckoutSession.State

ValueDescription
STATE_UNSPECIFIED
STATE_OPENWaiting for the customer.
STATE_PROCESSINGThe customer finished and the payment has not settled yet — a bank debit, for one. The credit arrives when it does.
STATE_PAIDPaid. `ledger_entry` is set once the credit has been granted, which is the webhook's doing and can trail this by a moment.
STATE_EXPIREDClosed without payment.

LedgerEntry.Type

ValueDescription
TYPE_UNSPECIFIED
TYPE_PLAN_GRANTMonthly plan credit granted.
TYPE_PURCHASECredit bought with a card or on invoice.
TYPE_PROMOTIONAL_GRANTPromotional or goodwill credit.
TYPE_USAGE_CHARGEUsage charged. The overwhelmingly common entry type.
TYPE_REFUNDMoney returned to the customer's payment method.
TYPE_ADJUSTMENTOperator correction, always with a reason.
TYPE_EXPIRYUnspent non-rolling grant removed at period end.
TYPE_REVERSALCharge reversed, e.g. after a failed provision that was still metered.
TYPE_PLAYER_TOP_UPCredit a player bought for a project, through a game's own store. Distinct from `TYPE_PURCHASE` because the person who paid is not the account holder and did not pay Plany: they paid a distributor, the developer was paid by the distributor, and Plany is owed by the developer. A statement that filed it as a purchase would read as a receipt for money the account holder never spent. Always in a project purse. See `plany.encore.v1`.

Purse

Purse is which of an account's credit balances something draws on.

Almost everything draws on the general balance, which is where plan credit and top-ups go. PURSE_UNSPECIFIED means the general balance: it is a real answer rather than an error, and it is what you will see on nearly every entry.

When the general balance is exhausted the account's workloads stop and their data is kept for 90 days, with a weekly reminder, before it is deleted.

ValueDescription
PURSE_UNSPECIFIEDThe general balance: plan credit and purchased credit. Unset means this.
PURSE_GENERALExplicitly the general balance, for a caller that wants to say so.
PURSE_PROJECTOne project's own balance, for a project that is top-up only. Every other purse is keyed by *what* is being bought; this one is keyed by *where*, because the credit in it was paid for a particular project — by that game's players, through Encore — and spending it anywhere else would be spending somebody else's money. A project purse therefore draws every SKU charged inside its project, and no plan credit, allowance or discount ever reaches it. Never meaningful on its own: whatever carries it also carries the project. Exhausting it stops that project's workloads and suspends nothing else.

QueryCostsRequest.GroupBy

Dimension to break spend down by.

ValueDescription
GROUP_BY_UNSPECIFIED
GROUP_BY_SKU
GROUP_BY_PROJECT
GROUP_BY_SERVICE
GROUP_BY_LOCATION
GROUP_BY_RESOURCE
GROUP_BY_LABEL
GROUP_BY_DAY
GROUP_BY_HOUR

Subscription.State

ValueDescription
STATE_UNSPECIFIED
STATE_ACTIVEPaid up. Each renewal grants the period's credit.
STATE_PAST_DUEA renewal failed and Stripe is retrying it. No credit is granted for the period until it is paid.
STATE_CANCELEDEnded — cancelled, or every retry failed. No more plan credit; purchased credit keeps working.
STATE_INCOMPLETECreated and never paid.
STATE_TRIALINGIn its free trial, which ends at `trial_end_time`. The trial's credit is granted; the first charge is at the trial's end.

PricingType

PricingType is how a SKU converts usage into money.

Every billable thing on Plany registers a SKU that names one of these. The brief calls for per-hour billing as the baseline with services free to choose their own pricing type, so the rating engine switches on this enum and nothing else — a new service becomes billable by inserting a SKU row, never by changing billing code.

ValueDescription
PRICING_TYPE_UNSPECIFIED
PRICING_TYPE_PER_HOURFlat charge for each hour the resource exists, regardless of size. quantity is hours. Example: a static IPv4 reservation.
PRICING_TYPE_PER_UNIT_HOURCharge per unit per hour. quantity is unit-hours. This is the workhorse: vCPU-hours, GiB-of-RAM-hours, GiB-of-disk-hours.
PRICING_TYPE_PER_UNIT_MONTHCharge per unit per month, prorated to the second over the calendar month's actual length. quantity is unit-months.
PRICING_TYPE_PER_UNIT_ONCEOne-off charge per unit, not time-based. quantity is units. Example: a snapshot export or a domain registration.
PRICING_TYPE_PER_REQUESTCharge per API request or per operation. quantity is requests. Normally priced per million with a large free allowance.
PRICING_TYPE_PER_GIB_TRANSFERCharge per GiB transferred. quantity is GiB. Egress bandwidth, the line item that most often surprises game hosting customers, so it gets its own type rather than hiding inside PER_UNIT_ONCE.
PRICING_TYPE_FLAT_MONTHLYFlat charge each month for the resource's existence, prorated on create and delete. quantity is months.
PRICING_TYPE_FREETracked for reporting and quota, and never charged.

TieringMode

TieringMode selects how PricingTier bands combine.

ValueDescription
TIERING_MODE_UNSPECIFIED
TIERING_MODE_FLATNo tiers; unit_price applies to the whole quantity.
TIERING_MODE_GRADUATEDEach band charges its own rate for the quantity falling inside it.
TIERING_MODE_VOLUMEThe band containing the total quantity sets the rate for all of it.