Create and list users, manage customer/project/account-code assignments, and resolve archive blockers.
On this page
8. Users
GET /users
| Parameter | In | Default | Notes |
|---|---|---|---|
UserList |
query | "" |
Comma-separated numeric IDs |
Status |
query | USER_STATUS_ALL |
USER_STATUS_ACTIVE (1), USER_STATUS_ARCHIVED (0), or USER_STATUS_ALL (0,1) |
StartRow |
query | 1 |
1-based |
MaxRows |
query | 50 |
Page size |
Returned columns include: UserID, LastName, FirstName, FullName, EmailAddress, Access, AdminUserID, EmployeeNumber, Location, Division, Department, JobTitle, UserStatus.
Pagination total field is spelled
totalrowsfround(legacy).
curl -s "$API_BASE/users?Status=USER_STATUS_ACTIVE&StartRow=1&MaxRows=25" \
-H "Authorization: Bearer $TOKEN" \
-H "apikey: $API_KEY"
curl -s "$API_BASE/users?UserList=101,102,103&Status=USER_STATUS_ALL" \
-H "Authorization: Bearer $TOKEN" \
-H "apikey: $API_KEY"
{
"errors": [],
"data": {
"users": [ { "UserID": 101, "FullName": "Jane Doe", "UserStatus": "1" } ],
"totalrowsfround": 42,
"startrow": "1",
"maxrows": "25"
}
}
POST /user
Creates a user in the caller’s company.
| Parameter | Required | Notes |
|---|---|---|
FirstName, LastName, EmailAddress |
Yes | |
PayType |
Yes | HOURLY / PAY_TYPE_HOURLY or SALARY / PAY_TYPE_SALARY |
AccessLevel |
Yes | ADMIN, SUPER, or EMP (constant names also accepted) |
TimezoneID |
Yes | From /server/timezones |
SupervisorID |
For SUPER/EMP | Report-to user |
JobTitle, EmployeeType |
No | |
DSTEnabled, SendNotificationEmail |
No | Booleans, default false |
EnableHourlyTracking, EnableProjectTracking, EnableExpenseReports |
No | EMP app flags |
curl -s -X POST "$API_BASE/user" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $TOKEN" \
-H "apikey: $API_KEY" \
-d '{
"FirstName": "Jane",
"LastName": "Doe",
"EmailAddress": "jane@example.com",
"PayType": "HOURLY",
"AccessLevel": "EMP",
"TimezoneID": 15,
"SupervisorID": 50,
"SendNotificationEmail": true,
"EnableHourlyTracking": true,
"EnableProjectTracking": true
}'
Success includes UserID, FirstName, LastName, FullName (and typically NewUserAdded). Business failures set errorCodes such as CreateUserInvalidPermission, CreateUserLicenseError, CreateUserValidationError.
9. User assignments (customers, projects, account codes)
Shared rules for all assignment endpoints:
- Require admin access to the target user’s profile.
PUT/POSTadd IDs without removing existing assignments.DELETEremoves only the supplied IDs.- Read-only or invalid IDs fail the entire request (no partial apply).
- Collection
DELETEs take IDs on the query string (no body).
Customers
| Method | Path | Body / query |
|---|---|---|
PUT |
/user/{UserID}/customer/{CustomerID} |
Optional IsDefault |
DELETE |
/user/{UserID}/customer/{CustomerID} |
— |
POST |
/user/{UserID}/customers |
CustomerID (csv), optional DefaultCustomerID |
DELETE |
/user/{UserID}/customers?CustomerID=... |
Query csv |
# Single assign + default
curl -s -X PUT "$API_BASE/user/101/customer/10" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $TOKEN" \
-H "apikey: $API_KEY" \
-d '{"IsDefault": true}'
# Batch assign
curl -s -X POST "$API_BASE/user/101/customers" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $TOKEN" \
-H "apikey: $API_KEY" \
-d '{"CustomerID":"10,11,12","DefaultCustomerID":10}'
# Batch unassign
curl -s -X DELETE "$API_BASE/user/101/customers?CustomerID=11,12" \
-H "Authorization: Bearer $TOKEN" \
-H "apikey: $API_KEY"
Removing the user’s default customer resets it to the company default.
Projects
Same pattern with ProjectID / DefaultProjectID / IsDefault:
curl -s -X PUT "$API_BASE/user/101/project/200" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $TOKEN" \
-H "apikey: $API_KEY" \
-d '{"IsDefault": true}'
curl -s -X POST "$API_BASE/user/101/projects" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $TOKEN" \
-H "apikey: $API_KEY" \
-d '{"ProjectID":"200,201,202","DefaultProjectID":200}'
curl -s -X DELETE "$API_BASE/user/101/projects?ProjectID=201,202" \
-H "Authorization: Bearer $TOKEN" \
-H "apikey: $API_KEY"
{
"errors": [],
"data": {
"UserID": 101,
"ItemIDList": "200,201,202",
"DefaultItemID": "200"
}
}
Account codes
Defaults are independent for hourly, project, and expense tracking. Default IDs must appear in the assign list and be enabled for that tracking type.
| Method | Path | Notable params |
|---|---|---|
PUT |
/user/{UserID}/accountcode/{AccountCodeID} |
IsDefaultHourly, IsDefaultProject, IsDefaultExpense |
DELETE |
/user/{UserID}/accountcode/{AccountCodeID} |
— |
POST |
/user/{UserID}/accountcodes |
AccountCodeID, DefaultHourlyAccountCodeID, DefaultProjectAccountCodeID, DefaultExpenseAccountCodeID |
DELETE |
/user/{UserID}/accountcodes?AccountCodeID=... |
Query csv |
curl -s -X PUT "$API_BASE/user/101/accountcode/30" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $TOKEN" \
-H "apikey: $API_KEY" \
-d '{"IsDefaultHourly": true, "IsDefaultExpense": true}'
curl -s -X POST "$API_BASE/user/101/accountcodes" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $TOKEN" \
-H "apikey: $API_KEY" \
-d '{
"AccountCodeID": "30,31,32",
"DefaultHourlyAccountCodeID": 30,
"DefaultProjectAccountCodeID": 31,
"DefaultExpenseAccountCodeID": 32
}'
curl -s -X DELETE "$API_BASE/user/101/accountcodes?AccountCodeID=31,32" \
-H "Authorization: Bearer $TOKEN" \
-H "apikey: $API_KEY"
10. Archive users
PATCH /user/{UserID}/archive
Archives the user. Optional DateOfTermination defaults to current UTC when omitted.
curl -s -X PATCH "$API_BASE/user/101/archive" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $TOKEN" \
-H "apikey: $API_KEY" \
-d '{"DateOfTermination": "2026-08-05"}'
errorCodes |
Meaning |
|---|---|
ArchiveUserInvalidPermission |
Missing permission / profile access |
ArchiveUserInvalidUserID |
User not in company |
ArchiveUserPrimaryContactError |
Cannot archive primary contact |
ArchiveUserSelfError |
Cannot archive yourself |
ArchiveUserOnclockError |
On the clock |
ArchiveUserOpenTimerError |
Open timers |
ArchiveUserUnpaidHours |
Unpaid hourly or project time |
ArchiveUserOpenExpenses |
Open expenses |
PATCH /user/{UserID}/archive/resolve
Clears resolvable blockers only — does not archive. All policies default to SKIP (empty body is a safe no-op).
| Parameter | Values | Default |
|---|---|---|
OnClockAction |
SKIP, FORCE_CLOCK_OUT |
SKIP |
OpenTimerAction |
SKIP, STOP_ALL |
SKIP |
PendingAlertAction |
SKIP, ALLOW, DENY, ALLOW_AND_APPROVE |
SKIP |
UnpaidHourlyAction |
SKIP, ARCHIVE, CLOSE, DELETE |
SKIP |
UnpaidProjectAction |
SKIP, ARCHIVE, DELETE |
SKIP |
OpenExpenseAction |
SKIP, RECONCILE, DELETE |
SKIP |
Resolution order: clock → timers → pending alerts → unpaid hourly → unpaid project → expenses.
Destructive actions need matching payroll / billing / expense permissions. Hard stops (permission, primary contact, self) are not auto-resolved.
curl -s -X PATCH "$API_BASE/user/101/archive/resolve" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $TOKEN" \
-H "apikey: $API_KEY" \
-d '{
"OnClockAction": "FORCE_CLOCK_OUT",
"OpenTimerAction": "STOP_ALL",
"PendingAlertAction": "ALLOW_AND_APPROVE",
"UnpaidHourlyAction": "ARCHIVE",
"UnpaidProjectAction": "ARCHIVE",
"OpenExpenseAction": "RECONCILE"
}'
Inspect data.actions for per-blocker outcomes, then call /archive.