> ## Documentation Index
> Fetch the complete documentation index at: https://docs.wealthyhood.com/llms.txt
> Use this file to discover all available pages before exploring further.

# User builder flow

> End-to-end guide for creating test users with specific statuses and properties in sandbox environments.

## Overview

This guide walks you through creating test users in sandbox environments. Use these test endpoints to quickly set up users in various lifecycle states for testing different scenarios.

<Warning>
  **Test endpoints are only available in development and staging environments.** They are disabled in production for security reasons. Always use the sandbox environment (`api.sandbox.wealthyhood.com`) when working with test endpoints.
</Warning>

<Info>
  All endpoints require an M2M bearer token. Test endpoints do not require the `x-user-id` header since they operate on test data.
</Info>

### Prerequisites

* API access and M2M credentials
* Sandbox environment access (development or staging)
* Understanding of user lifecycle states

***

## 1) Discover available user statuses

Before creating test users, retrieve the list of available user statuses to understand what test scenarios you can set up.

**Available statuses for B2B test user creation:**

* `INVESTED` - User with investments
* `INVESTED_WITH_CASH` - User with investments and cash balance
* `INVESTED_WITH_SAVINGS` - User with investments and savings

Only these three statuses are available for B2B test user creation. All users created via this endpoint will have investments, and optionally cash or savings.

Use `GET /test/help/statuses` to get all valid status values:

<CodeGroup>
  ```javascript Node.js theme={null}
  const BASE = 'https://api.sandbox.wealthyhood.com';

  async function getAvailableStatuses({ token }) {
    const res = await fetch(`${BASE}/test/help/statuses`, {
      headers: {
        'Authorization': `Bearer ${token}`,
        'Accept': 'application/json'
      }
    });
    if (!res.ok) throw new Error(`Failed to get statuses: ${res.status}`);
    const { statuses } = await res.json();
    return statuses;
  }

  // Get all available statuses
  const statuses = await getAvailableStatuses({ token: 'YOUR_M2M_TOKEN' });
  console.log('Available statuses:', statuses);
  ```

  ```bash cURL theme={null}
  curl -X GET 'https://api.sandbox.wealthyhood.com/test/help/statuses' \
    -H 'Accept: application/json' \
    -H 'Authorization: Bearer YOUR_M2M_TOKEN'
  ```
</CodeGroup>

***

## 2) Create a test user

Create a test user with a specific status. This sets up a user account in the desired lifecycle state with all associated data (accounts, addresses, KYC operations, portfolios, etc.).

Use `POST /test/users` to create a test user:

<CodeGroup>
  ```javascript Node.js theme={null}
  async function createTestUser({ token, email, status }) {
    const res = await fetch(`${BASE}/test/users`, {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${token}`,
        'Content-Type': 'application/json',
        'Accept': 'application/json'
      },
      body: JSON.stringify({ email, status })
    });
    if (!res.ok) {
      const error = await res.json();
      throw new Error(`Failed to create user: ${error.message || res.status}`);
    }
    const { user } = await res.json();
    return user;
  }

  // Example: Create an invested user with cash
  const user = await createTestUser({
    token: 'YOUR_M2M_TOKEN',
    email: 'test.user@example.com',
    status: 'INVESTED_WITH_CASH'
  });

  console.log('Created user ID:', user._id);
  console.log('User status:', user.status);
  console.log('Has portfolio:', user.portfolios?.length > 0);
  ```

  ```bash cURL theme={null}
  curl -X POST 'https://api.sandbox.wealthyhood.com/test/users' \
    -H 'Accept: application/json' \
    -H 'Content-Type: application/json' \
    -H 'Authorization: Bearer YOUR_M2M_TOKEN' \
    -d '{
      "email": "test.user@example.com",
      "status": "INVESTED_WITH_CASH"
    }'
  ```
</CodeGroup>

### Response example

```json theme={null}
{
  "user": {
    "_id": "64f0c51e7fb3fc001234abcd",
    "email": "test.user@example.com",
    "status": "INVESTED_WITH_CASH",
    "currency": "EUR",
    "portfolios": [...]
  }
}
```

<Check>
  The response includes the created user object with populated portfolios:

  * **portfolios** - User portfolios

  Save the `id` field for use in subsequent requests.
</Check>

### Request parameters

<ParamField body="email" type="string" required>
  Email address for the test user. Must be a valid email format. Use unique emails (e.g., include a timestamp) to avoid conflicts when running tests multiple times.
</ParamField>

<ParamField body="status" type="string" required>
  User status from the available statuses. Determines what data and relationships are created with the user (e.g., portfolios, cash balances).
</ParamField>

***

## 3) Verify user creation

Verify that the user was created successfully and check their details:

<CodeGroup>
  ```javascript Node.js theme={null}
  // The user object returned from createTestUser already contains all details
  console.log('User ID:', user._id);
  console.log('Email:', user.email);
  console.log('Status:', user.status);
  console.log('Currency:', user.currency);
  console.log('Portfolios:', user.portfolios?.length || 0);
  ```

  ```bash cURL theme={null}
  # The response from POST /test/users already contains all user details
  # No additional request needed
  ```
</CodeGroup>

***

## 4) Clean up test users (optional)

After completing your tests, clean up test users to keep your sandbox environment organized.

Use `DELETE /test/users` to delete a test user:

<CodeGroup>
  ```javascript Node.js theme={null}
  async function deleteTestUser({ token, email }) {
    const res = await fetch(`${BASE}/test/users`, {
      method: 'DELETE',
      headers: {
        'Authorization': `Bearer ${token}`,
        'Content-Type': 'application/json',
        'Accept': 'application/json'
      },
      body: JSON.stringify({ email })
    });
    if (!res.ok) throw new Error(`Failed to delete user: ${res.status}`);
    return res.ok;
  }

  // Clean up test user
  await deleteTestUser({
    token: 'YOUR_M2M_TOKEN',
    email: 'test.user@example.com'
  });
  ```

  ```bash cURL theme={null}
  curl -X DELETE 'https://api.sandbox.wealthyhood.com/test/users' \
    -H 'Accept: application/json' \
    -H 'Content-Type: application/json' \
    -H 'Authorization: Bearer YOUR_M2M_TOKEN' \
    -d '{
      "email": "test.user@example.com"
    }'
  ```
</CodeGroup>

### Response example

```http theme={null}
HTTP/1.1 200 OK
(No response body)
```

<Tip>
  Use this endpoint to clean up test users after completing your test scenarios to keep your sandbox environment tidy.
</Tip>

***

## Complete example

Here's a complete example that discovers statuses, creates a test user, and verifies the creation:

<CodeGroup>
  ```javascript Node.js theme={null}
  const BASE = 'https://api.sandbox.wealthyhood.com';
  const token = 'YOUR_M2M_TOKEN';

  async function createSandboxUserFlow() {
    try {
      // 1. Get available statuses
      const statusesRes = await fetch(`${BASE}/test/help/statuses`, {
        headers: {
          'Authorization': `Bearer ${token}`,
          'Accept': 'application/json'
        }
      });
      const { statuses } = await statusesRes.json();
      console.log('Available statuses:', statuses);

      // 2. Create test user
      const userRes = await fetch(`${BASE}/test/users`, {
        method: 'POST',
        headers: {
          'Authorization': `Bearer ${token}`,
          'Content-Type': 'application/json',
          'Accept': 'application/json'
        },
        body: JSON.stringify({
          email: `test-${Date.now()}@example.com`,
          status: 'INVESTED_WITH_CASH'
        })
      });
      const { user } = await userRes.json();
      console.log('Created user:', user._id);
      console.log('User status:', user.status);
      console.log('Portfolios:', user.portfolios?.length || 0);

      return user;
    } catch (error) {
      console.error('Error creating sandbox user:', error);
      throw error;
    }
  }

  createSandboxUserFlow();
  ```

  ```bash Shell script theme={null}
  #!/bin/bash

  BASE="https://api.sandbox.wealthyhood.com"
  TOKEN="YOUR_M2M_TOKEN"
  EMAIL="test-$(date +%s)@example.com"

  # 1. Get available statuses
  echo "Fetching available statuses..."
  STATUSES_RESPONSE=$(curl -s -X GET "${BASE}/test/help/statuses" \
    -H "Authorization: Bearer ${TOKEN}")

  echo "Available statuses:"
  echo $STATUSES_RESPONSE | jq '.statuses'

  # 2. Create test user
  echo "Creating test user..."
  USER_RESPONSE=$(curl -s -X POST "${BASE}/test/users" \
    -H "Authorization: Bearer ${TOKEN}" \
    -H "Content-Type: application/json" \
    -d "{\"email\": \"${EMAIL}\", \"status\": \"INVESTED_WITH_CASH\"}")

  USER_ID=$(echo $USER_RESPONSE | jq -r '.user._id')
  echo "Created user: ${USER_ID}"
  echo "User details:"
  echo $USER_RESPONSE | jq '.user | {_id, email, status, currency}'
  ```
</CodeGroup>

***

## Common use cases

### Creating users for investment testing

Create users with investments for testing investment orders:

```javascript theme={null}
// Create user with investments
const investor = await createTestUser({
  token,
  email: 'investor@example.com',
  status: 'INVESTED'
});

// User now has:
// - Portfolio with investments
// - Ready for investment order testing
```

### Creating users with cash for deposit testing

Create users with investments and cash for testing deposits and cash operations:

```javascript theme={null}
// Create user with investments and cash
const userWithCash = await createTestUser({
  token,
  email: 'cash@example.com',
  status: 'INVESTED_WITH_CASH'
});

// User now has:
// - Portfolio with investments
// - Cash balance
// - Ready for deposit and withdrawal testing
```

### Creating users with savings

Create users with investments and savings for testing savings-related features:

```javascript theme={null}
// Create user with investments and savings
const userWithSavings = await createTestUser({
  token,
  email: 'savings@example.com',
  status: 'INVESTED_WITH_SAVINGS'
});

// User now has:
// - Portfolio with investments
// - Savings account
// - Ready for savings order testing
```

***

## Next steps

After creating a sandbox user, you can:

* **Add deposits** - Use the [Sandbox payments flow](/flows/sandbox-payments) to simulate deposits
* **Test investment orders** - Submit orders using the [Order execution flow](/flows/order-execution)
* **Test withdrawals** - Create withdrawals using the [Cash movements flow](/flows/cash-movements)
* **Test savings orders** - Use the [Savings orders flow](/flows/savings-orders)

***

## Troubleshooting

### Invalid email format

**Error**: `400 - Invalid email format`

**Solution**: Ensure the email is a valid email address format (e.g., `user@example.com`).

### Invalid status

**Error**: `400 - Invalid status` or `Status must be one of: INVESTED, INVESTED_WITH_CASH, INVESTED_WITH_SAVINGS`

**Solution**: Only three statuses are allowed for B2B test user creation: `INVESTED`, `INVESTED_WITH_CASH`, and `INVESTED_WITH_SAVINGS`. Use `GET /test/help/statuses` to retrieve the list of valid status values. Ensure the status string matches exactly (case-sensitive).

### User already exists

**Error**: `400 - User already exists` or similar

**Solution**: Use unique email addresses for each test user. Include a timestamp or UUID in the email (e.g., `test-${Date.now()}@example.com`).

### Endpoint not available

**Error**: `403 - Forbidden` or endpoint returns 404

**Solution**: Verify you're using the sandbox environment (`api.sandbox.wealthyhood.com`). Test endpoints are disabled in production.

<Tip>
  Always use unique email addresses for test users to avoid conflicts. Consider including timestamps or UUIDs in email addresses when running tests multiple times.
</Tip>
