> For the complete documentation index, see [llms.txt](https://rest-api.symphony.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://rest-api.symphony.com/main/user-management/create-user-v2.md).

# Create User

Creates a new user, either End-User or Service User.

* End-User Accounts are assigned to employees. To create an end user account, the `accountType` field must be `NORMAL`.
* Service User Accounts are a type of account used for bots or applications, rather than end-users. To create a service user account, the `accountType` field must be `SYSTEM`.

See [User Attributes](ref:user-attributes), [Password Object](ref:password-object), and [Roles Object](ref:roles-object) for user creation parameters.

## POST /v2/admin/user/create

> Create a new V2 User

```json
{"openapi":"3.1.1","info":{"title":"Pod API","version":"20.17.1"},"servers":[{"url":"http://yourpodURL.symphony.com/pod"}],"paths":{"/v2/admin/user/create":{"post":{"summary":"Create a new V2 User","parameters":[{"schema":{"type":"string"},"name":"sessionToken","description":"Session authentication token.","in":"header","required":true}],"tags":["User"],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/V2UserDetail"}}}},"400":{"description":"Client error, see response body for further details.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized: Invalid session token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Forbidden: Caller lacks necessary entitlement.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Server error, see response body for further details.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/V2UserCreate"}}},"required":true}}}},"components":{"schemas":{"V2UserDetail":{"description":"V2 Detailed User record.","type":"object","properties":{"userAttributes":{"$ref":"#/components/schemas/V2UserAttributes"},"userSystemInfo":{"$ref":"#/components/schemas/UserSystemInfo"},"features":{"$ref":"#/components/schemas/IntegerList"},"apps":{"$ref":"#/components/schemas/IntegerList"},"groups":{"$ref":"#/components/schemas/IntegerList"},"roles":{"$ref":"#/components/schemas/StringList"},"disclaimers":{"$ref":"#/components/schemas/IntegerList"},"avatar":{"$ref":"#/components/schemas/Avatar"}}},"V2UserAttributes":{"description":"V2 User record.","type":"object","properties":{"emailAddress":{"type":"string"},"firstName":{"type":"string"},"lastName":{"type":"string"},"userName":{"type":"string"},"displayName":{"type":"string"},"companyName":{"type":"string"},"department":{"type":"string"},"division":{"type":"string"},"title":{"type":"string"},"workPhoneNumber":{"type":"string"},"mobilePhoneNumber":{"type":"string"},"twoFactorAuthPhone":{"type":"string"},"smsNumber":{"type":"string"},"accountType":{"type":"string","enum":["NORMAL","SYSTEM","SDL"]},"location":{"type":"string"},"recommendedLanguage":{"type":"string"},"jobFunction":{"type":"string"},"assetClasses":{"type":"array","items":{"type":"string"}},"industries":{"type":"array","items":{"type":"string"}},"marketCoverage":{"type":"array","items":{"type":"string"}},"responsibility":{"type":"array","items":{"type":"string"}},"function":{"type":"array","items":{"type":"string"}},"instrument":{"type":"array","items":{"type":"string"}},"currentKey":{"$ref":"#/components/schemas/V2UserKeyRequest"},"previousKey":{"$ref":"#/components/schemas/V2UserKeyRequest"},"userMetadata":{"type":"object","description":"Metadata map of key/values","additionalProperties":{"type":"object"}}}},"V2UserKeyRequest":{"description":"User RSA key information.","type":"object","properties":{"key":{"description":"User RSA public key.","type":"string"},"expirationDate":{"description":"RSA key expiration date. This value is set just for rotated keys.","type":"integer","format":"int64"},"action":{"description":"Action to be performed on the RSA key.\nThe following actions can be performed onto the user's active RSA key:\n  - SAVE\n  - REVOKE\nThe following actions can be performed onto the user's rotated RSA key:\n  - REVOKE\n  - EXTEND\n","type":"string"}}},"UserSystemInfo":{"description":"User Status Information.","type":"object","properties":{"id":{"type":"integer","format":"int64"},"status":{"type":"string","enum":["ENABLED","DISABLED"]},"suspended":{"type":"boolean","description":"An optional attribute indicating whether the user is temporarily suspended or not. Since SBE 20.14."},"suspendedUntil":{"type":"integer","format":"int64","description":"An optional unix timestamp until which the suspension is effective. Since SBE 20.14."},"suspensionReason":{"type":"string","description":"An optional description of the suspension reason. Since SBE 20.14."},"createdDate":{"type":"integer","format":"int64"},"createdBy":{"type":"string"},"lastUpdatedDate":{"type":"integer","format":"int64"},"lastLoginDate":{"type":"integer","format":"int64"},"lastPasswordReset":{"type":"integer","format":"int64"},"deactivatedDate":{"type":"integer","format":"int64"}}},"IntegerList":{"type":"array","items":{"type":"integer","format":"int64"}},"StringList":{"type":"array","items":{"type":"string"}},"Avatar":{"type":"object","properties":{"size":{"description":"The Avatar Size","type":"string"},"url":{"description":"Url of the image","type":"string"}}},"Error":{"type":"object","properties":{"code":{"type":"integer","format":"int32"},"message":{"type":"string"}}},"V2UserCreate":{"description":"V2 User Creation Object.\nAfter creation, modify roles, features etc via the specific API calls.\n","type":"object","properties":{"userAttributes":{"$ref":"#/components/schemas/V2UserAttributes"},"password":{"$ref":"#/components/schemas/Password"},"roles":{"type":"array","items":{"type":"string"}}}},"Password":{"description":"Password. Stored as derived password in both the Pod and the Key Manager using PBKDF2 function. Number of iterations should be 10000 and desired length 256 bits.","type":"object","properties":{"hSalt":{"description":"Pod password salt used for PBKDF2 derivation.","type":"string"},"hPassword":{"description":"Pod password derived with PBKDF2.","type":"string"},"khSalt":{"description":"Key Manager password salt used for PBKDF2 derivation.","type":"string"},"khPassword":{"description":"Key Manager password derived with PBKDF2.","type":"string"}}}}}}
```

### Request Examples

```bash
curl -X POST \
https://acme.symphony.com/pod/v2/admin/user/create \
-H "sessionToken: SESSION_TOKEN" \
-H "Content-Type: application/json" \
-d '{   
    "userAttributes": {
        "accountType": "NORMAL",
        "emailAddress": "janedoe@symphony.com",
        "firstName": "Jane",
        "lastName": "Doe",
        "userName": "janedoe",
        "displayName": "Jane Doe",
        "companyName": "",
        "department": "",
        "division": "",
        "title": "Sales",
        "twoFactorAuthPhone": "",
        "workPhoneNumber": "",
        "mobilePhoneNumber": "",
        "location": "San Francisco",
        "jobFunction": "Sales",
        "assetClasses": ["Commodities"],
        "industries": ["Basic Materials"],
        "marketCoverage": ["LATAM"],
        "responsibility": ["BAU"],
        "function": ["Trade Management"],
        "instrument": ["Securities"],
        "currentKey": {"key": "-----BEGIN PUBLIC KEY-----\nMIICIjAN...==\n-----END PUBLIC KEY-----"
}
        
    },
    "password": {
        "hSalt": "password",
        "hPassword": "password",
        "khSalt": "password",
        "khPassword": "password"
    }
}'
```

```bash
curl -X POST \
https://acme.symphony.com/pod/v2/admin/user/create \
-H "sessionToken: SESSION_TOKEN" -H "Content-Type: application/json" \
-d '{
  "userAttributes": {
    "accountType": "SYSTEM",
    "emailAddress": "apiuser@symphony.com",
    "userName": "apiuser",
    "displayName": "API User",
    "companyName": "Symphony",
    "department": "Client Application",
    "division": "Technology",
    "workPhoneNumber": "+33600000000",
    "mobilePhoneNumber": "+33600000001",
    "twoFactorAuthPhone": "+33600000002",
    "recommendedLanguage": "english",
    "location": "Sophia Antipolis",
    "jobFunction": "Sales",
    "assetClasses": ["Commodities"],
    "industries": ["Basic Materials"],
    "marketCoverage": ["LATAM"],
    "responsibility": ["BAU"],
    "function": ["Trade Management"],
    "instrument": ["Securities"],
    "currentKey": {
        "key": "-----BEGIN PUBLIC KEY-----MII...Q==-----END PUBLIC KEY-----"
    }

  },
  "roles": ["INDIVIDUAL", "USER_PROVISIONING", "SCOPE_MANAGEMENT", "CONTENT_MANAGEMENT", "MALWARE_SCAN_MANAGER", "MALWARE_SCAN_STATE_USER", "AUDIT_TRAIL_MANAGEMENT"]
}'
```

> #### 📘 Note - Suspension
>
> Since 20.14, `userSystemInfo` from the payload includes suspension info:
>
> * if user is active, then the `suspended` attribute is set to false,
> * if user is suspended, then the `suspended` attribute is set to true and both `suspendedUntil` and `suspensionReason` are as well included in the payload.
>
> *Please note that even if the suspendedUntil date is in the past, the user will remain suspended=true until he first logs on the client after the suspension ended. The suspended info are then automatically updated.*\
> See the [Suspend User Account](/main/user-management/suspend-user-v1.md) endpoint for more information.

> #### 🚧 Required Permissions
>
> Calling this endpoint requires the ACCESS\_USER\_PROVISIONING\_API and ACCESS\_ADMIN\_API privileges.\
> See [Bot Permissions](https://docs.developers.symphony.com/building-bots-on-symphony/configuration/bot-permissions) for a list of roles and associated privileges.

### The `Password` Object

The `password` object is optional for end-user accounts (`NORMAL`). For example, if your organization utilizes SSO, you may not want to specify the password.

*Please note the password object is not used for service accounts (`SYSTEM`) and therefore cannot be entered in the request payload.*

The following code snippets can be used to generate hashed passwords. Two implementations are provided, one using built-in Java classes and the other with Postman.

```java
@Test
public void test() throws NoSuchAlgorithmException, InvalidKeySpecException {
  String password = "ARandomPassword";
  SecureRandom sr = new SecureRandom();
  byte[] salt = new byte[16];
  sr.nextBytes(salt);
  assertTrue(Arrays.equals(generateStrongPasswordHash(password, salt), getSaltedPassword(password, salt)));
}

private static byte[] generateStrongPasswordHash(String password, byte[] salt)
throws NoSuchAlgorithmException, InvalidKeySpecException {
  int iterations = 10000;
  char[] pb = password.toCharArray();
  PBEKeySpec spec = new PBEKeySpec(pb, salt, iterations, 256);
  SecretKeyFactory skf = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
  byte[] hash = skf.generateSecret(spec).getEncoded();
  return hash;
}

public static byte[] getSaltedPassword(String password, byte[] salt) {
  PKCS5S2ParametersGenerator gen = new PKCS5S2ParametersGenerator(new SHA256Digest());
  byte[] bytes = password.getBytes(StandardCharsets.UTF_8);
  gen.init(bytes, salt, 10000);
  byte[] newPasswordGen = ((KeyParameter) gen.generateDerivedParameters(256)).getKey();
  return newPasswordGen;
}
```

```javascript
// Example with Postman, as a Pre-Request script.

const password = 'SymphonyRocks123456789!'; // Replace with your password

// Generate a random salt of specified length
function generateSalt(length) {
    return CryptoJS.lib.WordArray.random(128 / 8);
}

// PBKDF2 function using CryptoJS
function derivePBKDF2(password, salt, iterations, keyLength) {
    return CryptoJS.PBKDF2(password, salt, {
        keySize: keyLength / 32, // Key size in words (32-bit units)
        iterations: iterations,
        hasher: CryptoJS.algo.SHA256
    });
}

// Parameters
const iterations = 10000;           // Number of iterations
const keyLength = 256;              // Key length in bits (256 = 32 bytes)
const saltLength = 16;              // Salt length in characters

// Generate random salts
const hSalt = generateSalt(saltLength);
const khSalt = generateSalt(saltLength);

// Derive PBKDF2 hashes
const hPassword = derivePBKDF2(password, hSalt, iterations, keyLength);
const khPassword = derivePBKDF2(password, khSalt, iterations, keyLength);

// Convert salts and hashes to B64 strings
const hSaltB64 = CryptoJS.enc.Base64.stringify(hSalt);
const khSaltB64 = CryptoJS.enc.Base64.stringify(khSalt);
const hPasswordB64 = CryptoJS.enc.Base64.stringify(hPassword);
const khPasswordB64 = CryptoJS.enc.Base64.stringify(khPassword);

// Set Postman environment variables for use in the request
pm.environment.set('hSalt', hSaltB64);
pm.environment.set('hPassword', hPasswordB64);
pm.environment.set('khSalt', khSaltB64);
pm.environment.set('khPassword', khPasswordB64);
```
