Skip to content

Hold an organization's unpaid-plan escalation

The platform_billing.holds.set operation: PUT /api/v1/platform/organizations/{orgId}/billing_hold in the REST API and the platform_billing_holds_set tool in the MCP server.

PUT/api/v1/platform/organizations/{orgId}/billing_hold

Holds the escalation of an organization whose Ownrecord subscription is unpaid (spec §37.5): while the hold applies, the organization is at most at stage. Hold it where it is to stop it getting worse, hold it at active to lift a restriction or suspension, or give until to extend the current stage to a date. The status changes at once. The hold ends at until, when it is lifted (platform_billing.holds.lift), or when the subscription is paid. Platform admins only; the reason is recorded in the organization's audit log.

At a glance

  • REST: PUT /api/v1/platform/organizations/{orgId}/billing_hold
  • MCP tool: platform_billing_holds_set
  • Operation ID: platform_billing.holds.set
  • Scope: Platform
  • Permission: platform:admin
  • Risk tier: write
  • Dry run: Supported (send Ownrecord-Dry-Run: true)
  • Idempotency: Idempotency-Key optional
  • Modes: Test and live
  • Authentication: API key with the platform:admin scope
  • Fresh sign-in: In the console, a sign-in within the last 15 minutes
  • Since: M12

Request

Path parameters

FieldTypeDescription
orgIdorg_… IDThe organization (org_…).

Body

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

FieldTypeRequiredDescription
stageone of active, restricted, suspendedYesThe most severe stage while the hold applies.
untildate-timeNoWhen the hold ends (ISO 8601, in the future); left out, it lasts until lifted.
reasonstringYesWhy, for the audit log and the support team.

Response

200 OK with a JSON object:

FieldTypeDescription
object"platform_billing_hold"
orgIdstring
statusone of active, restricted, suspended, closing, closed
holdobject or null
unpaidSincedate-time or null
stageone of active, restricted, suspended or null
nextobject or null
billingOwnsStatusboolean

Examples

Keep an organization restricted, not suspended, until a bank transfer arrives

HTTP
PUT /api/v1/platform/organizations/org_01jbz3m4k5n6p7q8r9s0t1v2w3/billing_hold
Authorization: Bearer or_test_…
Content-Type: application/json

{
  "stage": "restricted",
  "until": "2026-11-15T00:00:00.000Z",
  "reason": "Paying by bank transfer; payment confirmed for 10 November"
}

Response (200):

JSON
{
  "object": "platform_billing_hold",
  "orgId": "org_01jbz3m4k5n6p7q8r9s0t1v2w3",
  "status": "restricted",
  "hold": {
    "stage": "restricted",
    "until": "2026-11-15T00:00:00.000Z",
    "reason": "Paying by bank transfer; payment confirmed for 10 November",
    "setBy": "usr_01jbz3m4k5n6p7q8r9s0t1v2w7"
  },
  "unpaidSince": "2026-10-05T09:12:00.000Z",
  "stage": "restricted",
  "next": {
    "stage": "suspended",
    "at": "2026-11-15T00:00:00.000Z"
  },
  "billingOwnsStatus": true
}

Errors

CodeHTTP statusWhenWhat to do
validation_failed400The organization ID, stage, reason or date is missing or malformed.Fix the fields listed in details.issues and send the request again.
platform_billing_hold_invalid400The hold ends in the past, or the organization's subscription isn't unpaid.Give a reason, a stage (active, restricted or suspended) and, to end it automatically, an until in the future.
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.
resource_not_found404There is no such organization.Check the ID and that your credentials are scoped to the right organization, entity, brand and mode.
permission_denied403Only a platform_admin holds an organization's escalation.Ask an organization owner or admin for a role or scope that allows this action.
fresh_auth_required403Your last sign-in is older than 15 minutes: sign in again first.Sign in again, then repeat the action within 15 minutes.

It can also return these common errors: api_version_unsupported, invalid_json, unsupported_media_type, authentication_required, api_key_invalid, idempotency_key_reused, idempotency_in_progress, rate_limited, internal_error.