Members

Change a member's role

Reassigns a member to a different role.

PATCH/members/{id}

Reassigns a member to a different role. roleId is the only mutable field, and role ids come from GET /roles.

Sending the member's current roleId is a no-op that still returns 200 with the unchanged member. You cannot change your own role (the key owner's membership), you cannot change the workspace owner's role, and you cannot promote anyone into the owner role.

Side effect worth knowing: after a successful change every API key owned by that member is re-clamped against the new role's permissions, so keys that held scopes the new role does not grant lose them immediately. Emits member.updated.

Requires the members:write scope.

curl --request PATCH \
  --url 'https://api.envless.cloud/members/<id>' \
  --header 'Authorization: Bearer ev_sk_xxxxxxxxxxxx' \
  --header 'Content-Type: application/json' \
  --data '{
  "roleId": "019faa4c-6f6e-716a-a548-fc2ea447953b"
}'
Try itPATCHhttps://api.envless.cloud/members/{id}
Path parameters

Authorization

  • Authorizationstringrequiredheader

    Bearer token: an Envless API key (ev_sk_…), created in the dashboard or with POST /keys. The key is bound to one workspace; every request runs inside it.

Path parameters

  • idstringrequired

    Workspace member id (the id from GET /members). This is not the user id, and no slug form is accepted.

Request body

application/json · required

  • roleIdstringrequired

    Target role id from GET /roles. Must belong to this workspace and must not be the owner role.

Responses

200OK

Change a member's role succeeded.

  • successbooleanrequired
  • codeintegerrequired

    The HTTP status of this response, repeated in the body.

  • messagestringrequired
  • errornullrequired
  • dataobjectrequired
    Show child attributesHide child attributes
    • idstringrequired

      Workspace member id. This is the id used by PATCH /members/{id} and the product-access routes.

    • roleobject | nullrequired
      Show child attributesHide child attributes
      • idstring
      • namestring
      • isSystemboolean
    • userobject | nullrequired
      Show child attributesHide child attributes
      • idstring
      • namestring
      • emailstring
      • avatarstring | null
    • createdAtstringrequireddate-time
  • _reqobject
    Show child attributesHide child attributes
    • reqIdstring
    • resTimeinteger | null
{
    "success": true,
    "code": 200,
    "message": "OK",
    "error": null,
    "data": {
        "id": "<string>",
        "role": {
            "id": "<string>",
            "name": "<string>",
            "isSystem": true
        },
        "user": {
            "id": "<string>",
            "name": "<string>",
            "email": "<string>",
            "avatar": "<string>"
        },
        "createdAt": "2026-05-30T10:14:22.000Z"
    },
    "_req": {
        "reqId": "<string>",
        "resTime": 1
    }
}

Error envelope

Every failure below returns the same shape with success: false; branch on error.code, never on message.

  • successbooleanrequired
  • codeintegerrequired

    The HTTP status of this response, repeated in the body.

  • messagestringrequired
  • errorobjectrequired

    Machine-readable failure detail. Null on success.

    Show child attributesHide child attributes
    • codeenum<string>required

      Stable error code. Branch on this, never on message.

      Options: "auth.api_key_required", "auth.api_key_not_found", "auth.api_key_user_missing", "auth.api_key_owner_not_member", "auth.scope_missing", "auth.scope_ceiling_exceeded", "auth.key_project_restricted", "auth.product_restricted", "auth.permission_denied", "auth.self_mutation_forbidden", "auth.step_up_required", "auth.step_up_fresh_required", "auth.cli_token_not_accepted", "auth.two_factor_required", "auth.workspace_two_factor_required", "auth.two_factor_invalid", "auth.two_factor_replayed", "auth.two_factor_locked", "auth.two_factor_not_enabled", "auth.two_factor_already_enabled", "request.body_must_be_json", "request.body_invalid", "request.body_too_large", "request.rate_limited", "request.invalid_pagination", "workspace.not_found", "workspace.slug_conflict", "workspace.limit_reached", "workspace.delete_last", "workspace.delete_too_early", "workspace.delete_has_projects", "domain.not_configured", "domain.not_found", "domain.invalid", "domain.taken", "domain.attempt_limit", "product.not_found", "product.slug_conflict", "product.locked", "project.not_found", "project.ambiguous_product", "project.slug_conflict", "environment.not_found", "environment.slug_conflict", "environment.expose_disabled", "environment.expose_private_product", "variable.not_found", "variable.name_conflict", "variable.ciphertext_invalid", "variable.baseline_drifted", "version.not_found", "member.not_found", "member.already_exists", "member.self_invite", "member.self_mutation", "member.owner_immutable", "member.owner_cannot_leave", "member.seat_limit", "invite.already_pending", "role.owner_not_assignable", "role.limit_reached", "role.immutable", "role.in_use", "invite.not_found", "invite.expired", "role.not_found", "role.name_conflict", "key.not_found", "key.limit_reached", "webhook.not_found", "webhook.delivery_not_found", "plan.limit_reached", "plan.upgrade_required", "request.not_found", "request.method_not_allowed", "request.conflict", "auth.unauthorized", "auth.forbidden", "request.invalid", "server.error"

    • resourcestring

      The resource or scope the failure relates to.

    • fieldstring

      The request field that caused the failure.

  • dataobject | nullrequired

    Null on most failures. A plan limit carries { limit, current }.

  • _reqobject
    Show child attributesHide child attributes
    • reqIdstring
    • resTimeinteger | null
{
    "success": false,
    "code": 400,
    "message": "Something went wrong.",
    "error": {
        "code": "auth.api_key_required",
        "resource": "<string>",
        "field": "<string>"
    },
    "data": {},
    "_req": {
        "reqId": "<string>",
        "resTime": 1
    }
}

400Bad Request

request.body_invalid - roleId is missing.

401Unauthorized

  • auth.api_key_required - the Authorization header is missing, or its value does not start with ev_sk_.
  • auth.api_key_not_found - the key is unknown, inactive or revoked.
  • auth.api_key_user_missing - the key is valid but its owner no longer exists.
  • auth.api_key_owner_not_member - the key's owner is no longer a member of the key's workspace.

403Forbidden

  • auth.scope_missing - the key lacks members:write.
  • auth.workspace_two_factor_required - the workspace requires two-factor authentication and the key's owner has not turned it on.

404Not Found

member.not_found - no member or role matches.

409Conflict

  • member.self_mutation - the key owner tried to change their own role.
  • member.owner_immutable - the target is the workspace owner.
  • role.owner_not_assignable - the owner role cannot be assigned to another member.

413Payload Too Large

request.body_too_large - the request body is larger than 1 MiB (1,048,576 bytes).

500Internal Server Error

server.error - an unexpected error; retry with backoff.

503Service Unavailable

server.error - the API is in maintenance mode or is missing its configuration; retry with backoff.