# Configure bot users

Bot users enable automated operations in Ripple Custody 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.

## Overview

A bot user differs from a human user in that 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


## Prerequisites

Before creating a bot user, you need:

| Prerequisite | Description |
|  --- | --- |
| **Admin user with API access** | An existing user who can propose intents |
| **Bot user key pair** | A secp256r1, secp256k1, or Ed25519 key pair for the bot user |
| **Your user and domain IDs** | See [Check your user information](/products/custody/v1.34/api/get-started/register#check-your-user-information) |
| **JWT token** | See [Authenticate API requests](/products/custody/v1.34/concepts/authenticate-api-requests) |


### Generate a key pair for the bot 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.


```bash
# Generate a P-256 (secp256r1) key pair
openssl ecparam -genkey -name prime256v1 -noout -out bot-private-key.pem

# Extract the public key in DER format with Base64 encoding
openssl ec -in bot-private-key.pem -pubout -outform DER | base64
```

Save the Base64-encoded public key—you'll use it in the next step.

## Create a bot user

Bot users are created through the intent workflow using the `v0_CreateUser` payload type.

### Step 1: Prepare the request object

Create a JSON file (`request.json`) with the bot user details:


```json
{
  "author": {
    "id": "<your-user-id>",
    "domainId": "<your-domain-id>"
  },
  "expiryAt": "2026-03-01T00:00:00.000Z",
  "targetDomainId": "<your-domain-id>",
  "id": "<new-intent-uuid>",
  "customProperties": {},
  "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"
  },
  "description": "Create bot user for automated operations",
  "type": "Propose"
}
```

Replace the placeholders:

| Placeholder | Value |
|  --- | --- |
| `<your-user-id>` | Your user ID (the admin creating the bot user) |
| `<your-domain-id>` | Your domain ID |
| `<new-intent-uuid>` | A new UUID for the intent (e.g., from `uuidgen`) |
| `<new-user-uuid>` | A new UUID for the bot user |
| `<bot-user-public-key-base64>` | The Base64-encoded public key from the key generation step |


### Step 2: Canonicalize and sign

Canonicalize the request and sign it with your private key:


```bash
# Canonicalize (sort keys, compact, no trailing newline)
cat request.json | jq -j -S -c > request_canonical.json

# Sign with your private key (P-256/secp256k1 on macOS)
SIGNATURE=$(openssl dgst -sha256 -sign your-private-key.pem request_canonical.json | base64 -b0)

# On Linux, use base64 -w0 instead of base64 -b0
```

### Step 3: Submit the intent

Build the full request body and submit it:


```bash
# Build the request body
REQUEST=$(cat request.json)
cat > intent_body.json << EOF
{
  "request": $REQUEST,
  "signature": "$SIGNATURE"
}
EOF

# Submit the intent
curl -X POST "https://{gateway}/v1/intents" \
  -H "Authorization: Bearer $JWT_TOKEN" \
  -H "Content-Type: application/json" \
  -d @intent_body.json
```

A successful response returns a request ID:


```json
{
  "requestId": "8737c2a2-e8e1-46bf-a2a4-9918437f4a29"
}
```

### Step 4: Approve the intent

The bot user creation intent requires approval according to your domain's policies. Another user with appropriate permissions must approve the intent before the bot user is created.

For approval instructions, see [Approve intents](/products/custody/v1.34/api/get-started/key-operations/update/intent-approval).

## Configure policies for auto-approval

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.

Configure policies based on the bot user's purpose:

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

For more information on configuring policies, see [Create policies](/products/custody/v1.34/api/environment/policy/create).

## Store credentials securely

Store the bot user's private key in a secure secrets management solution.

Kubernetes Secret

```bash
kubectl create secret generic bot-user-credentials \
  --from-file=private-key=./bot-private-key.pem
```

HashiCorp Vault

```bash
vault kv put secret/bot-user/credentials \
  private_key=@./bot-private-key.pem
```

AWS Secrets Manager

```bash
aws secretsmanager create-secret \
  --name bot-user/private-key \
  --secret-string file://bot-private-key.pem
```

### Security best practices

- Never commit private keys to version control
- Rotate keys periodically according to your security policy
- Use the principle of least privilege—grant only the permissions the bot user needs
- Monitor bot user activity through audit logs


## Verify the bot user

After the intent is approved and executed, verify the bot user can authenticate:

### Step 1: Generate a JWT for the bot user

Use the bot user's private key to obtain a JWT token. See [Authenticate API requests](/products/custody/v1.34/concepts/authenticate-api-requests) for the full procedure.

### Step 2: Test API access


```bash
curl -X GET "https://{gateway}/v1/domains/{domainId}/accounts" \
  -H "Authorization: Bearer $BOT_USER_JWT"
```

If the request returns successfully, the bot user is configured correctly.

## Related documentation

| Topic | Description |
|  --- | --- |
| [Authenticate API requests](/products/custody/v1.34/concepts/authenticate-api-requests) | Obtain JWT tokens and sign intents |
| [Create policies](/products/custody/v1.34/api/environment/policy/create) | Configure approval workflows and auto-approval |
| [Approve intents](/products/custody/v1.34/api/get-started/key-operations/update/intent-approval) | Approve the bot user creation intent |