Skip to content

User Provisioning

This guide covers creating and managing user accounts programmatically - useful for onboarding teams, automating employee lifecycle events, or integrating with an identity provider.


Prerequisites

Requirement Detail
Auth Active session + CSRF token
Privilege - read users/roles Users / View
Privilege - create/edit users Users / Edit

Step 1 - List Available Roles

Every user must be assigned a role. Fetch the role list to get role IDs before creating users.

curl -b cookies.txt "https://acme.knosc.com/api/role"

Response:

{
  "data": {
    "rows": [
      { "id": 1,  "Role Name": "Superuser",           "Role Description": "Full system access" },
      { "id": 3,  "Role Name": "Procurement Manager",  "Role Description": "Full procurement read/write, demand read" },
      { "id": 5,  "Role Name": "Demand Planner",       "Role Description": "Sales orders and forecasts read/write" },
      { "id": 7,  "Role Name": "Viewer",               "Role Description": "Read-only access to all modules" }
    ]
  }
}

Note the id for each role - you'll pass this as Role Id when creating a user.


Step 2 - Create a User

CSRF=$(grep csrf_access_token cookies.txt | awk '{print $NF}')

curl -b cookies.txt -X POST \
  "https://acme.knosc.com/api/user" \
  -H "Content-Type: application/json" \
  -H "X-XSRF-TOKEN: $CSRF" \
  -d '{
    "User Fullname": "Sarah Chen",
    "Username": "sarah.chen@acme.com",
    "User Email": "sarah.chen@acme.com",
    "User Phone": "+1 555 200 3000",
    "Role Id": 3,
    "password": "Welcome2024!"
  }'

Response:

{
  "message": "User created successfully.",
  "id": 88
}

The user will be prompted to change their password on first login.


Step 3 - Verify the User Was Created

curl -b cookies.txt "https://acme.knosc.com/api/user/88"
{
  "data": {
    "id": 88,
    "User Fullname": "Sarah Chen",
    "Username": "sarah.chen@acme.com",
    "User Email": "sarah.chen@acme.com",
    "User Phone": "+1 555 200 3000",
    "Role Id": 3,
    "Role Name": "Procurement Manager",
    "User Status": "Active"
  }
}

Step 4 - Update a User's Role

If a user changes teams or responsibilities, update their role with PUT:

curl -b cookies.txt -X PUT \
  "https://acme.knosc.com/api/user/88" \
  -H "Content-Type: application/json" \
  -H "X-XSRF-TOKEN: $CSRF" \
  -d '{"Role Id": 5}'

Only the fields included in the request body are modified.


Step 5 - Deactivate a User (Offboarding)

Set User Status to Inactive rather than deleting the account - this preserves audit history and any records created by that user.

curl -b cookies.txt -X PUT \
  "https://acme.knosc.com/api/user/88" \
  -H "Content-Type: application/json" \
  -H "X-XSRF-TOKEN: $CSRF" \
  -d '{"User Status": "Inactive"}'

Inactive users cannot log in but their historical data remains intact.


Bulk Provisioning - Python Example

import requests

BASE_URL = "https://acme.knosc.com/api"

def provision_users(session, users: list[dict]) -> list[dict]:
    """
    users: list of dicts with keys:
        fullname, username, email, phone (optional), role_id, password
    Returns list of results with user id or error per entry.
    """
    csrf = session.cookies.get("csrf_access_token")
    results = []

    for user in users:
        payload = {
            "User Fullname": user["fullname"],
            "Username": user["username"],
            "User Email": user["email"],
            "Role Id": user["role_id"],
            "password": user["password"],
        }
        if user.get("phone"):
            payload["User Phone"] = user["phone"]

        response = session.post(
            f"{BASE_URL}/user",
            headers={"X-XSRF-TOKEN": csrf},
            json=payload,
        )
        body = response.json()

        if response.status_code == 200:
            results.append({"username": user["username"], "id": body["id"], "status": "created"})
            print(f"  Created: {user['username']} (id={body['id']})")
        else:
            results.append({"username": user["username"], "error": body.get("Message"), "status": "failed"})
            print(f"  Failed:  {user['username']} - {body.get('Message')}")

    return results


# Fetch roles once
roles = {
    r["Role Name"]: r["id"]
    for r in session.get(f"{BASE_URL}/role").json()["data"]["rows"]
}

# Define users to provision
new_users = [
    {"fullname": "Alice Nguyen",  "username": "alice.nguyen@acme.com",  "email": "alice.nguyen@acme.com",  "role_id": roles["Procurement Manager"], "password": "Welcome2024!"},
    {"fullname": "Bob Okafor",    "username": "bob.okafor@acme.com",    "email": "bob.okafor@acme.com",    "role_id": roles["Demand Planner"],       "password": "Welcome2024!"},
    {"fullname": "Cate Patel",    "username": "cate.patel@acme.com",    "email": "cate.patel@acme.com",    "role_id": roles["Viewer"],               "password": "Welcome2024!"},
]

results = provision_users(session, new_users)
created = [r for r in results if r["status"] == "created"]
failed  = [r for r in results if r["status"] == "failed"]
print(f"\n{len(created)} created, {len(failed)} failed")

Password Policy

Rule Requirement
Minimum length 8 characters
Format Any printable characters
First-login reset Users are prompted to set a new password on their first successful login

Set a temporary password when provisioning; users change it on first sign-in. Avoid sending the temporary password in plain text - use a secure channel (e.g. encrypted email, 1Password Send).


Checking Existing Users Before Provisioning

To avoid User.AlreadyExists errors, check if a username or email is already in use before calling POST:

users = session.get(f"{BASE_URL}/user").json()["data"]["rows"]
existing_emails = {u["User Email"] for u in users}

to_create = [u for u in new_users if u["email"] not in existing_emails]
already_exists = [u for u in new_users if u["email"] in existing_emails]

print(f"{len(to_create)} to create, {len(already_exists)} already exist")

Common Errors

Code Cause Fix
User.AlreadyExists Username or User Email already taken Check existing users first; use a unique identifier
User.PasswordTooShort Password shorter than 8 characters Use a longer temporary password
Role.NotFound Role Id does not match any role Fetch roles first and use the correct id
User.NotPrivileged Your account lacks Users / Edit privilege Contact your administrator