1. Home
  2. Account Management
  3. Tools
  4. API Workflows, Errors & Client Examples

API Workflows, Errors & Client Examples

API documentation hub

End-to-end integration workflows, common failure modes, and reusable Bash, Node.js, and Python clients.

On this page

  1. 15. End-to-end workflows
  2. 16. Common errors
  3. 17. Client snippets

15. End-to-end workflows

A — Create user and assign work context

# 1) Create
USER_JSON=$(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,
    "EnableHourlyTracking":true,"EnableProjectTracking":true
  }')
# Parse UserID from USER_JSON when errors is empty

USER_ID=101

# 2) Assign customers, projects, account codes
curl -s -X POST "$API_BASE/user/$USER_ID/customers" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $TOKEN" -H "apikey: $API_KEY" \
  -d '{"CustomerID":"10,11","DefaultCustomerID":10}'

curl -s -X POST "$API_BASE/user/$USER_ID/projects" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $TOKEN" -H "apikey: $API_KEY" \
  -d '{"ProjectID":"200,201","DefaultProjectID":200}'

curl -s -X POST "$API_BASE/user/$USER_ID/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
  }'

B — Offboard (resolve blockers → archive)

USER_ID=101

curl -s -X PATCH "$API_BASE/user/$USER_ID/archive" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $TOKEN" -H "apikey: $API_KEY" \
  -d '{"DateOfTermination":"2026-08-05"}'

# If errorCodes include resolvable blockers:
curl -s -X PATCH "$API_BASE/user/$USER_ID/archive/resolve" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $TOKEN" -H "apikey: $API_KEY" \
  -d '{
    "OnClockAction":"FORCE_CLOCK_OUT",
    "OpenTimerAction":"STOP_ALL",
    "UnpaidHourlyAction":"ARCHIVE",
    "UnpaidProjectAction":"ARCHIVE",
    "OpenExpenseAction":"RECONCILE"
  }'

curl -s -X PATCH "$API_BASE/user/$USER_ID/archive" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $TOKEN" -H "apikey: $API_KEY" \
  -d '{"DateOfTermination":"2026-08-05"}'

C — Look up items then assign

# Find customers
curl -s "$API_BASE/items/customer?FullTextSearch=acme&MaxRows=10" \
  -H "Authorization: Bearer $TOKEN" -H "apikey: $API_KEY"

# Assign one found ID as 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}'


16. Common errors

Symptom Likely cause
HTTP 401 Missing/invalid apikey or Bearer token; auth mismatch; archived API user
HTTP 420 Rate limit exceeded
"errors": [...] with HTTP 200 Validation or business rule failure — treat as failure
Read-only item message Cannot assign/unassign that customer/project/account code
Default ID rejected Not in assign list, or wrong tracking type for account codes
Archive hard-stop codes Primary contact / self / permission — resolve manually
ArchiveUserResolutionInvalidPolicy Typo in policy enum
Collection DELETE validation error Forgot query-string ID list (body is ignored)


17. Client snippets

Bash helper

api() {
  local method="$1" path="$2" body="${3:-}"
  if [[ -n "$body" ]]; then
    curl -s -X "$method" "$API_BASE$path" \
      -H "Content-Type: application/json" \
      -H "Authorization: Bearer $TOKEN" \
      -H "apikey: $API_KEY" \
      -d "$body"
  else
    curl -s -X "$method" "$API_BASE$path" \
      -H "Authorization: Bearer $TOKEN" \
      -H "apikey: $API_KEY"
  fi
}

api GET "/health-check"           # health needs no headers — call curl directly
api GET "/users?Status=USER_STATUS_ACTIVE&MaxRows=5"
api POST "/user/101/customers" '{"CustomerID":"10,11","DefaultCustomerID":10}'
api DELETE "/user/101/projects?ProjectID=201"
api PATCH "/user/101/archive" '{"DateOfTermination":"2026-08-05"}'

Node.js (fetch)

const API_BASE = process.env.API_BASE;
const headers = {
  Authorization: `Bearer ${process.env.TOKEN}`,
  apikey: process.env.API_KEY,
  "Content-Type": "application/json",
};

async function api(method, path, body) {
  const res = await fetch(`${API_BASE}${path}`, {
    method,
    headers,
    body: body ? JSON.stringify(body) : undefined,
  });
  const json = await res.json();
  if (json.errors?.length) {
    const err = new Error(json.errors.join(" | "));
    err.errorCodes = json.errorCodes || [];
    err.response = json;
    throw err;
  }
  return json.data ?? json;
}

await api("GET", "/items/customer?MaxRows=10");
await api("POST", "/user/101/projects", { ProjectID: "200,201", DefaultProjectID: 200 });
await api("PATCH", "/user/101/archive/resolve", {
  OnClockAction: "FORCE_CLOCK_OUT",
  OpenTimerAction: "STOP_ALL",
  UnpaidHourlyAction: "ARCHIVE",
  UnpaidProjectAction: "ARCHIVE",
  OpenExpenseAction: "RECONCILE",
});
await api("PATCH", "/user/101/archive", { DateOfTermination: "2026-08-05" });

Python (requests)

import os
import requests

API_BASE = os.environ["API_BASE"]
HEADERS = {
    "Authorization": f"Bearer {os.environ['TOKEN']}",
    "apikey": os.environ["API_KEY"],
    "Content-Type": "application/json",
}

def api(method, path, json=None, params=None):
    r = requests.request(method, f"{API_BASE}{path}", headers=HEADERS, json=json, params=params)
    r.raise_for_status()
    payload = r.json()
    if payload.get("errors"):
        raise RuntimeError(f"{payload['errors']} codes={payload.get('errorCodes', [])}")
    return payload.get("data", payload)

api("GET", "/server/timezones")
api("PUT", "/user/101/accountcode/30", json={"IsDefaultHourly": True})
api("DELETE", "/user/101/customers", params={"CustomerID": "11,12"})
api("GET", "/report/user/info", params={"UserList": "101,102"})

API documentation hub

Updated on August 20, 2026
Was this article helpful?

Related Articles