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.
/api/v1/platform/maintenanceTurns 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-Keyrequired - Modes: Test and live
- Authentication: API key with the
platform:adminscope - 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):
| Field | Type | Required | Description |
|---|---|---|---|
on | boolean | Yes | true turns it on, false off. |
reason | string | Yes | Why (kept in the audit log). Never paste personal data or secrets here. |
Response
200 OK with a JSON object:
| Field | Type | Description |
|---|---|---|
object | "platform_maintenance" | |
on | boolean | While on, requests answer 503 and job runner passes do nothing. |
reason | string or null | Why it was last switched. |
since | date-time or null | When it was last switched (null: never). |
by | string or null | Who switched it last: a user (usr_…) or a system actor. |
retryAfterSeconds | integer | What Retry-After says to callers while it is on. |
Examples
Before a point-in-time restore
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):
{
"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
| Code | HTTP status | When | What to do |
|---|---|---|---|
resource_not_found | 404 | The 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_conflict | 409 | The platform settings changed at the same time; retry. | Fetch the object again and retry the change. |
validation_failed | 400 | The reason is missing or too long. | Fix the fields listed in details.issues and send the request again. |
fresh_auth_required | 403 | You last signed in more than 15 minutes ago. | Sign in again, then repeat the action within 15 minutes. |
permission_denied | 403 | You 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.