Skip to content

Pricing Plans

Pricing plans describe what your app charges, on the app itself. Plans render on your marketplace listing (the pricing section and the "From $X/mo" summary), and the Billing API can price charges from them, so what sellers see on the listing and what you charge never drift apart.

Plans are managed from the Partners dashboard under Apps > your app > Pricing.

Plan fields

FieldDescription
handleUnique identifier per app, referenced by the Billing API. Lowercase letters, numbers, and hyphens. Generated from the name, editable.
nameDisplay name on the listing and the seller's confirmation page.
typerecurring or onetime.
pricePrice in USD. min:0.00, max:1000.00.
intervalRecurring plans only: 30 (monthly) or 365 (yearly).
trial_daysRecurring plans only: free trial days, min:0, max:90.
featuresFeature bullets shown on the listing's pricing cards. Max 10.
is_freeMarks a free tier. Price is forced to zero.
is_visibleHidden plans do not render on the listing but stay available to the Billing API by handle, which is how custom per-seller deals work.

An app can have at most 12 plans.

Charging with a plan handle

Pass the plan's handle when creating a charge and the charge is priced from the catalog. Price, interval, and trial come from the plan, so a price change in the dashboard applies to new charges without an app deploy.

json
// POST /billing/apps/charges/recurring
{
  "name": "Pro",
  "return_url": "https://myapp.com/billing/success",
  "plans": [{ "type": "time_based", "handle": "pro" }]
}
json
// POST /billing/apps/charges/onetime
{
  "name": "Lifetime unlock",
  "return_url": "https://myapp.com/billing/success",
  "plan_handle": "lifetime"
}

An unknown handle, or a handle whose plan type does not match the endpoint, returns 422.

trial_days on the request overrides the plan's trial when present.

Raw charges still work

The Billing API is unchanged for existing integrations: raw amounts stay first-class, and nothing requires a catalog. A raw charge that matches a catalog plan (same amount, interval, and trial days) is linked to that plan automatically, and charges created before the catalog existed link up when you add a matching plan later. Linked charges carry the plan's id as plan_id in API responses.

Raw amounts remain the right tool for genuinely dynamic pricing, usage-style amounts, or one-off negotiated charges. For the charges you make repeatedly, your standard tiers, create plans first and reference them by handle:

  • Your listing advertises exactly what you charge, and stays correct when prices change.
  • Price changes happen in the dashboard and apply to new charges without an app deploy.
  • Charges resolve to a plan, so you can tell which tier a store is on.

TIP

Keep listing and reality in sync: reference plans by handle from your app, and treat the dashboard as the single place where prices change.