---
title: "User management command (Admin+step-up); typed reason, expected version, audit event"
method: POST
path: "/api/v1/admin/users/{id}/actions"
tags: ["admin"]
---

# User management command (Admin+step-up); typed reason, expected version, audit event

`POST /api/v1/admin/users/{id}/actions`

## Request

- Base URL: `https://amplerun-api.spiry.org`
- URL: `https://amplerun-api.spiry.org/api/v1/admin/users/{id}/actions`
- Auth: HTTP bearer

One of five commands. Every one requires an admin session with an enrolled TOTP factor, a fresh `admin-sensitive` step-up grant, an Idempotency-Key, a typed reason and the `expected_version` read from GET /api/v1/admin/users/{id}. A stale version is 409 STALE_VERSION and writes nothing. There is no balance action here and there must never be one.

`set_role` and `set_suspension` are refused with 409 CONFLICT when they would leave the system with zero admins; the check locks the admin set inside the transaction, so two demotions racing cannot both succeed.

`set_suspension` blocks sign-in and every API key on the next request and stops new admissions for the account, but never cancels a running rental: it keeps metering and billing to funded expiry or stop. `reset_mfa` clears the enrolment and every session so the user must re-enrol; it never reveals or sets a secret.

## Path parameters

- `id` string, required

## Headers

- `Idempotency-Key` string, uuid, required

## Request body

- union
  - object
    - `action` 'set_role', required
    - `role` 'renter' | 'host' | 'admin', required
    - `reason` string, required
    - `expected_version` string, required
  - object
    - `action` 'set_host_capability', required
    - `enabled` boolean, required
    - `reason` string, required
    - `expected_version` string, required
  - object
    - `action` 'set_suspension', required
    - `suspended` boolean, required
    - `reason` string, required
    - `expected_version` string, required
  - object
    - `action` 'revoke_sessions' | 'reset_mfa', required
    - `reason` string, required
    - `expected_version` string, required

## Response `200`

Applied. Returns the new version, what changed and the stated consequence.

## Other responses

- `409`: Error envelope. 401 unauthenticated, 403/404 forbidden, 409 conflict, 422 invalid input, 429 rate limited (code UNAVAILABLE, retryable:true, no Retry-After header), 503 unavailable money/provider state with retryable:true.
- `default`: Error envelope. 401 unauthenticated, 403/404 forbidden, 409 conflict, 422 invalid input, 429 rate limited (code UNAVAILABLE, retryable:true, no Retry-After header), 503 unavailable money/provider state with retryable:true.

---

[API](https://skmtc.dev/amplerun/apis/amplerun-business-api.md) · [All operations](https://skmtc.dev/amplerun/apis/amplerun-business-api/llms.txt) · [OpenAPI document](https://skmtc.dev/amplerun/apis/amplerun-business-api/revisions/40944687fa52?raw)
