Skip to content

Turn maintenance mode on or off

The platform.maintenance.set operation: POST /api/v1/platform/maintenance in the REST API and the platform_maintenance_set tool in the MCP server.

POST/api/v1/platform/maintenance

Turns maintenance mode on or off (docs/runbooks/restore-drill.md). While it is on, every request to the app answers 503 service_maintenance with Retry-After (the API, MCP, the console, checkout and the portal alike), except the health endpoint (which reports it) and the platform console's maintenance page with the sign-in it needs; job runner passes, kicked or from the cron, do nothing, so no email, webhook or charge goes out. Turn it on before a restore and off once the restored database is verified. Switching to the state it is in already changes nothing.

Platform admins only, after signing in within the last 15 minutes, with a reason (kept in the audit log). Also available as pnpm --filter @ownrecord/jobs maintenance against a database directly (a restored copy).

At a glance

  • REST: POST /api/v1/platform/maintenance
  • MCP tool: platform_maintenance_set
  • Operation ID: platform.maintenance.set
  • Scope: Platform
  • Permission: platform:admin
  • Risk tier: security
  • Dry run: Supported (send Ownrecord-Dry-Run: true)
  • Idempotency: Idempotency-Key required
  • 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: M13

Request

Body

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

FieldTypeRequiredDescription
onbooleanYestrue turns it on, false off.
reasonstringYesWhy (kept in the audit log). Never paste personal data or secrets here.

Response

200 OK with a JSON object:

FieldTypeDescription
object"platform_maintenance"
onbooleanWhile on, requests answer 503 and job runner passes do nothing.
reasonstring or nullWhy it was last switched.
sincedate-time or nullWhen it was last switched (null: never).
bystring or nullWho switched it last: a user (usr_…) or a system actor.
retryAfterSecondsintegerWhat Retry-After says to callers while it is on.

Examples

Before a point-in-time restore

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

{
  "on": true,
  "reason": "Point-in-time restore after a bad migration (incident 2026-11-03)."
}

Response (200):

JSON
{
  "object": "platform_maintenance",
  "on": true,
  "reason": "Point-in-time restore after a bad migration (incident 2026-11-03).",
  "since": "2026-11-03T09:00:00.000Z",
  "by": "usr_01m5wvkry1e6w94sjxgme33fsa",
  "retryAfterSeconds": 120
}

Errors

CodeHTTP statusWhenWhat to do
resource_not_found404The platform settings don't exist yet (run the platform bootstrap).Check the ID and that your credentials are scoped to the right organization, entity, brand and mode.
version_conflict409The platform settings changed at the same time; retry.Fetch the object again and retry the change.
validation_failed400The reason is missing or too long.Fix the fields listed in details.issues and send the request again.
fresh_auth_required403You last signed in more than 15 minutes ago.Sign in again, then repeat the action within 15 minutes.
permission_denied403You aren't a platform admin.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, idempotency_key_required, idempotency_key_reused, idempotency_in_progress, rate_limited, internal_error.