# Manage users and roles

Use this page for post-genesis user operations and role assignment. You can define role names whenever you need them, but standard user-management changes assign roles through governed user intents. The invitation API is a separate user-creation flow that also carries role names. For the model, see [Users and roles](/products/custody/governance/users). For launch planning, see [Plan your first users](/products/custody/governance/genesis/plan-your-first-users).

## User actions

| Action | UI procedure | API procedure |
|  --- | --- | --- |
| Create a user | [Create a user in the UI](#create-a-user-in-the-ui) | [Create a user with the API](#create-a-user-with-the-api) |
| Invite a user | [Invite a user in the UI](#invite-a-user-in-the-ui) | [Invite a user with the API](#invite-a-user-with-the-api) |
| View users and roles | [View users and roles in the UI](#view-users-and-roles-in-the-ui) | [View users and roles with the API](#view-users-and-roles-with-the-api) |
| Update a user | [Update a user in the UI](#update-a-user-in-the-ui) | [Update a user with the API](#update-a-user-with-the-api) |
| Lock and unlock a user | [Lock or unlock a user in the UI](#lock-or-unlock-a-user-in-the-ui) | [Lock or unlock a user with the API](#lock-or-unlock-a-user-with-the-api) |
| Configure a bot user | Use the API procedure. | [Configure a bot user with the API](#configure-a-bot-user-with-the-api) |


## API reference and shared process

| Task | API reference |
|  --- | --- |
| Propose a user intent | [Propose an intent](/products/custody/reference/api/openapi/intents/createintent) |
| Dry run a user intent | [Perform a dry run](/products/custody/reference/api/openapi/intents/intentdryrun) |
| Get current user | [Get current user](/products/custody/reference/api/openapi/users/getme) |
| Get known roles | [Get known user roles](/products/custody/reference/api/openapi/users/getknownuserroles) |
| Create user invitation | [Create a user invitation](/products/custody/reference/api/openapi/user-invitations/paths/~1v1~1domains~1{domainid}~1users~1invitations/post) |
| Complete user invitation | [Complete a user invitation](/products/custody/reference/api/openapi/user-invitations/paths/~1v1~1domains~1{domainid}~1users~1invitations~1{id}~1complete/post) |


Standard user changes, including role assignment changes, use the intent flow. The invitation API provides a separate user-creation flow. For signing, approval, and status checks for user intents, see [Manage intents and approvals](/products/custody/governance/intents/manage-intents-and-approvals), [Sign intents](/products/custody/identity-and-access/authentication/authenticate-api-requests#signing-intents-state-mutation-operations), and [Check updates](/products/custody/governance/intents/manage-intents-and-approvals#check-state).

## Role assignment model

Roles are role-name strings. You do not create roles as separate governed resources. You can introduce a role name when you use it in a user, policy, or domain read access configuration.

After genesis, a role affects a user through one of the user creation or update flows:

- Use `v0_CreateUser` to create a user with one or more roles.
- Use `v0_UpdateUser` to add, remove, or replace a user's roles.
- Use the invitation API to create an invited user with role names in the invitation user object.


Use [Get known user roles](/products/custody/reference/api/openapi/users/getknownuserroles) to reuse existing role names and avoid typos. The known-role list is not a prerequisite for defining a new role name.

## Common operations

| Operation | Intent type | Use when |
|  --- | --- | --- |
| Create user | `v0_CreateUser` | Add a human user or bot user. |
| Update user | `v0_UpdateUser` | Change alias, role assignments, login providers, description, or custom properties. |
| Lock user | `v0_LockUser` | Suspend user access. |
| Unlock user | `v0_UnlockUser` | Restore user access. |


## Create a user in the UI

1. Go to **Administration > Users**.
2. Click **Create new user manually**.
3. Enter the user details.
4. Click **Submit for Approval**.
5. Sign the operation with the mobile app.


The user is created after the intent is approved and executed.

Enter these details when creating a user:

| Field | Details |
|  --- | --- |
| Alias | Email address or other user-friendly identifier. Users in the same domain cannot share an alias. Users with the same public key in different domains must use the same alias. |
| Login providers | At minimum, add the internal login provider `harmonize`. Add external SSO providers only when they are configured for your environment by Ripple. |
| Login ID | User alias configured for the identity provider. For the internal provider, this is usually the user's email address. |
| User public key | Public key generated during registration. You can enter the key manually or scan it from the mobile app by clicking the QR code icon, then asking the user to open their profile and select **Show my public key**. |
| Roles | One or more roles. Select existing roles or enter new role names. In the standard create-user flow, the system assigns the roles only after approvers approve the user-creation intent and the system executes it. |
| Custom properties | Optional string metadata for your operational model. |


Before creating a user, collect the user's alias, public key, roles, and login provider details. For SSO values, use only provider IDs configured for your environment.

## Create a user with the API

Create a user by submitting a `v0_CreateUser` intent.

Before you create a user, prepare:

| Prerequisite | Additional information |
|  --- | --- |
| Role names | Call [Get known user roles](/products/custody/reference/api/openapi/users/getknownuserroles) if you want to reuse existing role names. You can also include new role names because the user creation or update flow carries role assignments. |
| New IDs | Prepare a user ID and intent ID in standard UUID format. |
| Public key | The user provides this during registration. |
| Login providers | Include internal `harmonize` login details and any configured SSO provider aliases and provider IDs. |



```json
{
  "payload": {
    "id": "61aaa805-f9b8-11eb-b158-dcfb48cfb3cb",
    "alias": "operator@example.com",
    "publicKey": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE7ItVC+y2KerttcRjPLDs8QmDVz7yI7ElQA70Sz+cLcBI6041aObPvcNqps8eTYe2jhc2Kb5qgNgoACB3SqpYIA==",
    "roles": ["transaction-operator"],
    "loginIds": [
      {
        "id": "operator@example.com",
        "providerId": "harmonize"
      }
    ],
    "lock": "Unlocked",
    "description": "Transaction operator",
    "customProperties": {},
    "type": "v0_CreateUser"
  }
}
```

Dry run before submitting:


```sh
curl -X POST "${CUSTODY_API_URL}/v1/intents/dry-run" \
  -H "Authorization: Bearer ${JWT_TOKEN}" \
  -H "Content-Type: application/json" \
  -d @create-user-intent.json
```

## Invite a user

Invitations automate the step where a new human user communicates their public key. You cannot use this flow for bot users.

### Invite a user in the UI

1. Go to **Administration > Users**.
2. Click **Invite a user**.
3. Enter the user details.
4. Click **Create the invitation**.
5. Share the invitation with the user. In **Pending users**, click **Copy URL to share** and send it to the user.
6. The user opens the URL, downloads the authenticator app, and creates a profile. The app sends the public key back to the UI.
7. In **Pending users**, expand the user row.
8. Click **Submit for approval**.
9. Sign the operation with the mobile app.


### Invite a user with the API

Create and share an invitation:


```json
{
  "numberSecondsOfValidity": 634302,
  "user": {
    "id": "4dddcc15-b6b8-4ed7-83cd-d3950c6b2063",
    "alias": "invited-user@example.com",
    "roles": ["operator", "risk"],
    "customProperties": {},
    "lock": "Unlocked"
  }
}
```

The invitation body includes:

- `alias`: User-friendly identifier, such as an email address.
- `roles`: One or more role names for the invited user.
- `numberSecondsOfValidity`: Invitation validity period in seconds.


Share the returned invitation `id` or `code` with the user. The user fills the invitation by calling the fill-invitation operation with the public key:


```json
{
  "publicKey": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE7ItVC+y2KerttcRjPLDs8QmDVz7yI7ElQA70Sz+cLcBI6041aObPvcNqps8eTYe2jhc2Kb5qgNgoACB3SqpYIA=="
}
```

Filling an invitation does not require authentication because the user does not exist yet. After the user responds, complete the invitation. If the invitation expires or is no longer needed, renew or cancel it with the same invitation ID and domain ID shape:


```json
{
  "id": "f1d73f89-8ab7-4758-9919-e479670e45a5",
  "domainId": "5cd224fe-193e-8bce-c94c-c6c05245e2d1"
}
```

The completion response contains the invitation user details, including the user's ID, alias, roles, and public key. User invitations are an alternative method to create users. Use `v0_UpdateUser` if you need to change the user's roles after invitation completion.

## View users and roles

### View users and roles in the UI

In the UI, go to **Administration > Users** to view users, pending invitations, lock state, and assigned roles.

### View users and roles with the API

Use [Get current user](/products/custody/reference/api/openapi/users/getme) to list users that belong to the same public key as the current user. The response includes the public key and domains for the user:


```json
{
  "publicKey": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE7ItVC+y2KpbztcRjPLDs8QmDVz7yI7ElQA70Sz+cLcBI6041aObPvcNqps8eTYe2jhc2Kb5qgNgoACB3SqpYIA==",
  "domains": [
    {
      "id": "67241e7d-f345-459e-9293-475693c45d85",
      "alias": "My root domain",
      "userReference": {
        "id": "61aaa805-f9b8-11eb-b158-dcfb48cfb3cb",
        "alias": "operator@example.com"
      }
    }
  ]
}
```

Use [Get known user roles](/products/custody/reference/api/openapi/users/getknownuserroles) to list role names already known in a domain. Use this list to reuse existing names and avoid spelling differences; you can still introduce a new role name through a user, policy, or domain read access change.

## Update a user

Use `v0_UpdateUser` to change a user's role assignments. Treat role elevation as a high-risk governance action.

### Update a user in the UI

1. Go to **Administration > Users**.
2. At the end of the user row, click the contextual menu and select **Edit**.
3. Update the email address, login providers, role assignments, or custom properties.
4. Click **Submit for Approval**.
5. Sign the operation with the mobile app.


### Update a user with the API


```json
{
  "payload": {
    "reference": {
      "id": "61aaa805-f9b8-11eb-b158-dcfb48cfb3cb",
      "revision": 2
    },
    "alias": "operator@example.com",
    "roles": ["transaction-operator", "transaction-supervisor"],
    "loginIds": [
      {
        "id": "operator@example.com",
        "providerId": "harmonize"
      }
    ],
    "description": "Transaction operator with supervisor role",
    "customProperties": {},
    "type": "v0_UpdateUser"
  }
}
```

Before updating role assignments:

- Compare current and proposed roles.
- Check whether the user gains maker or checker capability.
- Check whether quorum assumptions change.
- Confirm that the approving policy is strong enough for privilege changes.


## Lock and unlock a user

Lock users during investigations, employment changes, leave, or suspected key compromise.

### Lock or unlock a user in the UI

1. Go to **Administration > Users**.
2. At the end of the user row, click the contextual menu.
3. Select **Lock** or **Unlock**.
4. Click **Submit for Approval**.
5. Sign the operation with the mobile app.


### Lock or unlock a user with the API


```json
{
  "payload": {
    "reference": {
      "id": "61aaa805-f9b8-11eb-b158-dcfb48cfb3cb",
      "revision": 2
    },
    "type": "v0_LockUser"
  }
}
```

Use `v0_UnlockUser` only after confirming the user should regain access and still has the correct roles.

## Configure a bot user with the API

Bot users enable automated operations by allowing services to authenticate and sign transactions programmatically. Use bot users for automated workflows such as gas funding, scheduled transfers, or integration with external systems.

A bot user differs from a human user because it:

- Authenticates using a key pair rather than interactive login.
- Performs operations automatically without human intervention.
- Requires policies configured for auto-approval to function unattended.


Before creating a bot user, prepare:

| Prerequisite | Description |
|  --- | --- |
| Admin user with API access | Existing user that can propose intents. |
| Bot user key pair | Dedicated secp256r1, secp256k1, or Ed25519 key pair for the bot user. |
| User and domain IDs | IDs for the admin user and target domain. |
| JWT token | Token for the proposing user. |


Generate a dedicated key pair for the bot user. The public key is included in the user creation request; the private key is used by the bot to authenticate.


```sh
openssl ecparam -genkey -name prime256v1 -noout -out bot-private-key.pem
openssl ec -in bot-private-key.pem -pubout -outform DER | base64
```

Save the Base64-encoded public key for the `v0_CreateUser` intent.


```json
{
  "payload": {
    "id": "<new-user-uuid>",
    "alias": "gas-station-bot@example.com",
    "publicKey": "<bot-user-public-key-base64>",
    "roles": ["operator"],
    "loginIds": [
      {
        "id": "gas-station-bot@example.com",
        "providerId": "harmonize"
      }
    ],
    "lock": "Unlocked",
    "description": "Bot user for Gas Station automated funding",
    "customProperties": {},
    "type": "v0_CreateUser"
  }
}
```

Submit, sign, and approve the bot user creation intent using the standard user intent flow. After approval and execution, verify the bot user by generating a JWT with the bot user's private key and testing a read operation the bot should be allowed to perform.

For fully automated operation, create policies that allow automatic approval of the bot user's transactions. Without auto-approval, transactions created by the bot user queue for manual approval.

| Use case | Intent types | Additional restrictions |
|  --- | --- | --- |
| Gas Station | `v0_CreateTransactionOrder` | Native token transfers only, specific source accounts. |
| Scheduled transfers | `v0_CreateTransactionOrder` | Specific source/destination accounts. |
| Account management | `v0_CreateAccount` | Specific domains. |


If your organization's policies require additional approvers for the bot user's transactions, automated workflows will not function automatically. Transactions will queue for manual approval.

Store the bot user's private key in a secure secrets management solution, such as a Kubernetes Secret, HashiCorp Vault, or AWS Secrets Manager. Never commit private keys to version control, rotate keys periodically according to your security policy, grant only the permissions the bot user needs, and monitor bot user activity through audit logs.

## Operational checklist

Before submitting a user-management intent:

- Confirm the target domain.
- Confirm the role names match policies.
- Confirm approvers can see user and request details.
- Confirm quorum can be satisfied without the target user.
- Dry run the payload.


For user fields and role naming guidance, see [User and role reference](/products/custody/governance/users/reference).