Skip to content

Change the organization's Ownrecord plan

The platform_billing.change_plan operation: POST /api/v1/platform_billing/plan in the REST API and the platform_billing_change_plan tool in the MCP server.

POST/api/v1/platform_billing/plan

Moves the organization to another Ownrecord plan (starter, growth or scale; sandbox to go back to the free plan) and billing interval (month or year where the plan has a yearly price):

  • Upgrade with a card on file: applies now, invoiced at once with the unused time credited; the old plan stays until the payment succeeds.
  • Upgrade without a card (for example from sandbox): the answer is outcome: checkout with checkoutUrl, Ownrecord's own checkout, where you save a card and pay the first invoice. The plan changes when it is paid.
  • Downgrade: scheduled for the end of the current period (outcome: scheduled), with no credit.

Plans are priced in EUR, CHF and USD: pass currency, or leave it out to keep a running paid plan's currency (or, from the free plan, take the suggestion for your country: CHF for Switzerland and Liechtenstein, EUR for the EU, USD otherwise). A running paid plan keeps its currency. Every paid plan includes the volume fee on live payments, billed monthly in arrears in the plan's currency. Invoices come from Ownrecord's entity, Etna Labs AG in Switzerland, with tax (Swiss VAT for Swiss customers, reverse charge for businesses abroad with a valid VAT ID). Only an org_owner or billing_admin can change the plan. Dry-run it to see what happens without changing anything.

At a glance

  • REST: POST /api/v1/platform_billing/plan
  • MCP tool: platform_billing_change_plan
  • Operation ID: platform_billing.change_plan
  • Scope: Organization
  • Permission: platform_plan:admin
  • Risk tier: financial
  • Dry run: Supported (send Ownrecord-Dry-Run: true)
  • Idempotency: Idempotency-Key required
  • Modes: Test and live
  • Authentication: API key with the platform_plan:admin scope
  • Since: M12

Request

Body

A JSON object (Content-Type: application/json):

FieldTypeRequiredDescription
planstringYesThe plan key, e.g. growth.
intervalone of month, yearNoThe billing interval of the plan's fee.
currencystringNoThe subscription's currency: EUR, CHF or USD (default: the running plan's, else your country's).

Response

200 OK with a JSON object:

FieldTypeDescription
object"platform_plan_change"
orgIdstring
planstring
intervalone of month, year
currencystring
outcomeone of changed, scheduled, checkout
subscriptionIdstring
effectiveAtdate-time or null
checkoutUrlstring or null

Examples

Upgrade from Sandbox to Growth

No card is on file, so the answer is Ownrecord's checkout.

HTTP
POST /api/v1/platform_billing/plan
Authorization: Bearer or_test_…
Idempotency-Key: 3f1c9a52-7d0e-4b8f-9a61-0c2d5e8b7f14
Content-Type: application/json

{
  "plan": "growth",
  "interval": "month"
}

Response (200):

JSON
{
  "object": "platform_plan_change",
  "orgId": "org_01jbz3m4k5n6p7q8r9s0t1v2w3",
  "plan": "growth",
  "interval": "month",
  "currency": "EUR",
  "outcome": "checkout",
  "subscriptionId": "sub_01jbz3m4k5n6p7q8r9s0t1v2w6",
  "effectiveAt": null,
  "checkoutUrl": "https://ownrecord.io/c/ownrecord/cs_01jbz3m4k5n6p7q8r9s0t1v2w9?key=…"
}

Upgrade a Swiss organization to Growth in Swiss francs

HTTP
POST /api/v1/platform_billing/plan
Authorization: Bearer or_test_…
Idempotency-Key: 3f1c9a52-7d0e-4b8f-9a61-0c2d5e8b7f14
Content-Type: application/json

{
  "plan": "growth",
  "interval": "month",
  "currency": "CHF"
}

Response (200):

JSON
{
  "object": "platform_plan_change",
  "orgId": "org_01jbz3m4k5n6p7q8r9s0t1v2w3",
  "plan": "growth",
  "interval": "month",
  "currency": "CHF",
  "outcome": "checkout",
  "subscriptionId": "sub_01jbz3m4k5n6p7q8r9s0t1v2w6",
  "effectiveAt": null,
  "checkoutUrl": "https://ownrecord.io/c/ownrecord/cs_01jbz3m4k5n6p7q8r9s0t1v2w9?key=…"
}

Downgrade to Starter at the end of the period

HTTP
POST /api/v1/platform_billing/plan
Authorization: Bearer or_test_…
Idempotency-Key: 3f1c9a52-7d0e-4b8f-9a61-0c2d5e8b7f14
Content-Type: application/json

{
  "plan": "starter",
  "interval": "month"
}

Response (200):

JSON
{
  "object": "platform_plan_change",
  "orgId": "org_01jbz3m4k5n6p7q8r9s0t1v2w3",
  "plan": "starter",
  "interval": "month",
  "currency": "EUR",
  "outcome": "scheduled",
  "subscriptionId": "sub_01jbz3m4k5n6p7q8r9s0t1v2w5",
  "effectiveAt": "2026-11-01T00:00:00.000Z",
  "checkoutUrl": null
}

Errors

CodeHTTP statusWhenWhat to do
validation_failed400The plan key, interval or currency is missing or malformed.Fix the fields listed in details.issues and send the request again.
platform_plan_unknown400There's no self-serve plan with this key, or it has no price for the interval or currency.Pick one of the plans platform_billing.get lists under plans (enterprise is arranged with sales; internal is never sold).
platform_plan_currency_fixed409A paid plan is running in another currency: it keeps its currency (move to the free plan first).Choose the plan in the currency it is billed in, or move to the free plan first and then choose the plan in the new currency.
platform_plan_unchanged409The organization is already on this plan and interval.Choose another plan or interval, or leave the plan as it is.
platform_plan_change_pending409An upgrade is still waiting for its payment in a checkout.Finish the checkout you started (its link is on the billing page), or wait until it expires (23 hours), then try again.
platform_billing_details_required409A paid plan needs the organization's VAT ID: add a legal entity, or billing details in the portal.Add your legal entity (its VAT ID is used), or enter your billing details and VAT ID in Organization → Billing → billing portal, then change the plan again.
platform_billing_unavailable409Ownrecord's plans aren't set up on this installation yet.A platform admin runs pnpm platform:bootstrap, which creates the plans, prices and features of data/platform/plans.yaml. Try again afterwards.
platform_customer_missing409The organization's billing account is still being set up (dry runs).Wait a few seconds and reload the billing page. If it persists, contact support.
permission_denied403Only an org_owner or billing_admin changes the plan.Ask an organization owner or admin for a role or scope that allows this action.

It can also return these common errors: api_version_unsupported, invalid_json, unsupported_media_type, authentication_required, api_key_invalid, resource_not_found, idempotency_key_required, idempotency_key_reused, idempotency_in_progress, approval_required, approval_rejected, approval_expired, stale_approval, approval_policy_denied, rate_limited, internal_error.