User-creation endpoints

Every endpoint that lets a logged-in user (or an API caller) create another user account in Tasklife. Covers the web admin form, the self-service agent form, the public REST API, and the closely-related credential/manager endpoints you will need immediately after creating a user.

Audience: a developer integrating Tasklife with another system (CI provisioning, signup sync, partner onboarding) who needs to know which programmatic endpoints exist today, what each one accepts, and what gaps remain.
Not covered: marketing signup (signup.php, free-tier only), OAuth registration of MCP clients, and the admin CLI.

Which endpoint should I use?

Use case Endpoint Auth User types Sets manager?
Self-service: any user adds an agent they will manage POST /main/api/profile_create_agent.php Session agent only Yes — caller becomes the manager
Org admin onboarding a human teammate or a bot via the UI POST /admin/admin_user_add.php Session + is_org_admin human or agent Yes — manager picker in the form
External automation provisioning an agent under an API key POST /v1/agents API key (role=org_admin) agent only No — set with reports_to_org_user_id via the web admin today
Programmatic creation of a human user Not yet exposed — — —
Known gap. The public REST API can create agent users (POST /v1/agents) but does not expose a POST /v1/users endpoint for human users. The GET and PATCH /v1/users/{id} endpoints exist, but creation is admin-UI only today. The reports_to_org_user_id column also has no public-API PATCH endpoint; manager assignment after creation still requires the admin UI or a direct DB write by an operator.

POST /main/api/profile_create_agent.php

Self-service endpoint any logged-in user can call to create an agent in the org they are currently viewing. The calling user becomes the new agent's manager (org_users.reports_to_org_user_id). Used by the "Create Agent" button on /main/profile.php.

Request

JSON body, session cookie required.

POST /main/api/profile_create_agent.php HTTP/1.1
Host: tasklife.com
Content-Type: application/json
Cookie: PHPSESSID=...

{
  "name":   "Cody the Coder",
  "handle": "cody",
  "email":  "[email protected]"
}
FieldTypeRequiredNotes
namestringyesDisplay name. Max 255 chars.
handlestringyesUnique across all orgs. Pattern: /^[a-zA-Z0-9_]+$/, max 50 chars.
emailstringoptionalIf blank, a synthetic email (agent+<org>_<token>@agents.stracker.local) is generated. If provided, must pass FILTER_VALIDATE_EMAIL.

Response (201-style success)

{
  "success": true,
  "data": {
    "user": {
      "id": 142,
      "org_user_id": 211,
      "name": "Cody the Coder",
      "handle": "cody",
      "email": "[email protected]",
      "user_type": "agent",
      "org_id": 12,
      "reports_to_org_user_id": 79,
      "status": "active"
    }
  }
}

Errors

HTTPcodeWhen
422VALIDATIONMissing/invalid name, handle, or email. error.fields lists each problem.
409HANDLE_TAKENHandle already exists in org_users or users.
403NO_MEMBERSHIPCaller has no org_users row in their current org.
422NO_ORG_CONTEXTSession has no org_id.
401UNAUTHORIZEDNot logged in.

curl example

curl -sS -X POST https://tasklife.com/main/api/profile_create_agent.php \
  -H 'Content-Type: application/json' \
  -b 'PHPSESSID=YOUR_SESSION' \
  -d '{"name":"Cody the Coder","handle":"cody","email":"[email protected]"}'

POST /admin/admin_user_add.php

Admin web form. Accepts either application/x-www-form-urlencoded body (default browser submit) or a JSON-style action under ui_access_action. The form supports both human and agent user types, lets the admin pick a manager via a typeahead, and can optionally email the new login credentials back to the admin.

Request (form-encoded)

POST /admin/admin_user_add.php HTTP/1.1
Host: tasklife.com
Content-Type: application/x-www-form-urlencoded
Cookie: PHPSESSID=...

name=Cody+the+Coder
&user_type=agent
&email=
&handle=cody
&status=active
&reports_to_org_user_id=79
&new_password=
&address=
&city=
&state=
&postal_code=
&country=
FieldTypeRequiredNotes
namestringyesDisplay name.
user_typeenumyeshuman or agent.
emailstringrequired for human, optional for agentSynthetic email generated for agents when blank.
handlestringoptionalPattern /^[a-zA-Z0-9_]+$/.
statusenumdefault activeactive, inactive, etc.
reports_to_org_user_idintoptionalMust reference an active org_users.id in the same org. Setting this is how you assign a manager.
new_passwordstringoptionalIf set, must be ≥ 4 chars. Stored as bcrypt hash.
address / city / state / postal_code / countrystringoptionalPersisted on org_users.
ui_access_action=email_payloadstringoptionalIf set, posts an email with the credentials payload to ui_access_email.

Response

Standard PHP form response: redirects with a success_message or error_message query string. The credentials payload (if a password was supplied) is also stashed in the admin session for one-time display/copy on the form.

Notes

Source: admin/admin_user_add.php lines 99-247.


POST /v1/agents

Public REST API endpoint for creating agent users. Requires an API key whose org_users.role = 1 (org admin). The new agent is created in the org the API key belongs to. This is the entry point an external CI/automation pipeline uses for bot onboarding.

Request

POST /v1/agents HTTP/1.1
Host: api.tasklife.com
Authorization: Bearer tsk_xxx...your_api_key
Content-Type: application/json

{
  "display_name": "Cody the Coder",
  "handle":       "cody",
  "role":         2,
  "description":  "On-call CI fix-it bot"
}
FieldTypeRequiredNotes
display_name (or name)stringyesGoes into users.name.
handlestringoptionalPattern: /^[a-z0-9][a-z0-9._-]{1,63}$/i. If set, must be unique inside the API key's org.
roleintoptional, default 21 = org admin, 2 = member, 3 = read-only. Invalid values fall back to 2.
descriptionstringoptionalCurrently not persisted; included for forward-compat.

Response (201)

{
  "success": true,
  "data": {
    "agent": {
      "id":              142,
      "org_user_id":     211,
      "display_name":    "Cody the Coder",
      "handle":          "cody",
      "role":            2,
      "org_id":          12,
      "user_type":       "agent",
      "created_at":      "2026-08-23T18:42:11+00:00"
    }
  }
}

Errors

HTTPcode / messageWhen
400display_name is requiredEmpty name.
400Invalid handle formatHandle fails regex.
409Handle already in use in this orgHandle collision.
403Admin access requiredAPI key's org role ≠ 1.
401missing/invalid Authorization: BearerAPI key auth failed upstream.

curl example

curl -sS -X POST https://api.tasklife.com/v1/agents \
  -H "Authorization: Bearer $TASKLIFE_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"display_name":"Cody the Coder","handle":"cody","role":2}'

What POST /v1/agents does NOT do

Source: external-api/v1/index.php lines 1502-1512 and main/api/lib/AgentUsersService.php::createAgent().


After creation: what's next?

For an agent you will typically follow up with one or more of these calls:

Endpoint Purpose
POST /v1/agents/{id}/credentials Mint a long-lived API key for the agent. Only the plaintext key returned at creation time is ever shown again — Tasklife stores a hash. Capture it client-side immediately.
POST /v1/agents/{id}/credentials/{key_id}/rotate Rotate an existing credential; old plaintext is invalidated.
POST /v1/agents/{id}/token/mint Mint a one-time Agent UI login token (1-120 min TTL). Agent follows the returned target_url, completes OAuth device-grant, and lands authenticated.
GET /v1/agents/{id}/invitation Returns an MCP invitation bundle (handle + setup URL, no plaintext key) the admin can hand to the agent's operator.
PATCH /v1/users/{org_user_id} Update handle and webhook config for an existing user. Not yet wired for reports_to_org_user_id; that still requires the admin UI.

See /docs/api/agents/ for full per-endpoint reference and /docs/mcp/ for the MCP server side of the OAuth device-grant flow.


Data model in 60 seconds

Tasklife stores a person as two rows:

Every API payload you receive uses both ids: id is the users.id (global), org_user_id is the org_users.id (per-org). Manager relationships are org_users.reports_to_org_user_id pointing at another org_users.id in the same org — an org can have multiple managers, and any user (human or agent) can be a manager. The column is nullable; a NULL value means "Top" (reports to no one).


Page version: 2026-08-23. Authoritative source of truth for the public REST API lives in external-api/v1/index.php; for the web forms, in admin/admin_user_add.php and main/api/profile_create_agent.php.