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

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

Operation: `adminUserAction`.

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

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.

## Endpoint

`POST https://amplerun-api.spiry.org/api/v1/admin/users/{id}/actions`

## Authentication

Admin interactive session. API keys do not authorize administrative operations. Sensitive writes also require the stated fresh step-up proof; account MFA is configurable.

## Parameters

| Name | Location | Presence | Type | Description |
| --- | --- | --- | --- | --- |
| `id` | path | Required | string |  |
| `Idempotency-Key` | header | Required | UUID | UUID scoped to authenticated principal, route and canonical request hash. |

## Request body

Required body. 

### `application/json`

```json
{
  "oneOf": [
    {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "action",
        "role",
        "reason",
        "expected_version"
      ],
      "properties": {
        "action": {
          "type": "string",
          "enum": [
            "set_role"
          ]
        },
        "role": {
          "type": "string",
          "enum": [
            "renter",
            "host",
            "admin"
          ]
        },
        "reason": {
          "type": "string",
          "minLength": 5,
          "maxLength": 2000
        },
        "expected_version": {
          "type": "string",
          "minLength": 1
        }
      }
    },
    {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "action",
        "enabled",
        "reason",
        "expected_version"
      ],
      "properties": {
        "action": {
          "type": "string",
          "enum": [
            "set_host_capability"
          ]
        },
        "enabled": {
          "type": "boolean"
        },
        "reason": {
          "type": "string",
          "minLength": 5,
          "maxLength": 2000
        },
        "expected_version": {
          "type": "string",
          "minLength": 1
        }
      }
    },
    {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "action",
        "suspended",
        "reason",
        "expected_version"
      ],
      "properties": {
        "action": {
          "type": "string",
          "enum": [
            "set_suspension"
          ]
        },
        "suspended": {
          "type": "boolean"
        },
        "reason": {
          "type": "string",
          "minLength": 5,
          "maxLength": 2000
        },
        "expected_version": {
          "type": "string",
          "minLength": 1
        }
      }
    },
    {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "action",
        "reason",
        "expected_version"
      ],
      "properties": {
        "action": {
          "type": "string",
          "enum": [
            "revoke_sessions",
            "reset_mfa"
          ]
        },
        "reason": {
          "type": "string",
          "minLength": 5,
          "maxLength": 2000
        },
        "expected_version": {
          "type": "string",
          "minLength": 1
        }
      }
    }
  ]
}
```

## Responses

### `200`

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

### `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.

`application/json`
| Field | Type | Presence | Description |
| --- | --- | --- | --- |
| `error` | object | Required |  |

```json
{
  "$ref": "#/components/schemas/ErrorEnvelope"
}
```

### `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.

`application/json`
| Field | Type | Presence | Description |
| --- | --- | --- | --- |
| `error` | object | Required |  |

```json
{
  "$ref": "#/components/schemas/ErrorEnvelope"
}
```

## Static request outline

Replace path/query placeholders and provide the required JSON body, headers and credential from the sections above. This is a request outline, not a command that chooses an amount or starts a rental for you.

```sh
curl --request POST 'https://amplerun-api.spiry.org/api/v1/admin/users/{id}/actions'
```

[Schema definitions](https://docs.amplerun.com/reference/schemas.md) · [Download OpenAPI](/openapi.json) · [Authentication](https://docs.amplerun.com/agents/authentication.md) · [Errors and recovery](https://docs.amplerun.com/reference/errors.md)

---
Generated from the AmpleRun API contract.
Canonical: https://docs.amplerun.com/reference/api/admin-user-action/
