Skip to content

Tenant API v1 — Projects

Base path: /api/tenant/v1

Middleware: auth:tenant-api, tenant.user, not.suspended, verified, module:projects, plus permission middleware / policies.

No hard module_dependencies — Projects installs standalone. contact_id, company_id, and opportunity_id are optional; supplying any requires the corresponding module to be entitled (soft link rules).

Visibility without projects.assign (and not superadmin): list/board/stats/view/update only include projects where the actor is assignee, member, or creator. With projects.assign, org-wide (scope: org on stats).

Field name is title (not name).

Stats

GET /projects/stats

Same filters as list (minus pagination/sort). Response:

json
{
  "total_projects": 0,
  "my_projects": 0,
  "planned": 0,
  "active": 0,
  "active_projects": 0,
  "on_hold": 0,
  "completed": 0,
  "cancelled": 0,
  "overdue": 0,
  "overdue_projects": 0,
  "scope": "org | mine"
}

active / active_projects are the same count. overdue / overdue_projects count open projects (planned|active|on_hold) whose ends_on is before workspace-local today.

Board

GET /projects/board

One column per status (planned, active, on_hold, completed, cancelled): status, project_count, projects[]. Honors the same filters as list. Optional per_column (1–100, default 50).

Projects CRUD

GET /projects

Query: search (matches title), status, contact_id, company_id, opportunity_id, assigned_to (unassigned or user id), my_projects, overdue (open statuses with ends_on before workspace-local today), trashed (true|only), sort, direction, page, per_page.

List items include title, status, description, starts_on, ends_on, soft CRM refs, assignee/creator, members[], and latest_note.

POST /projects

Body: title (required), description, contact_id, company_id, opportunity_id, starts_on, ends_on (after_or_equal:starts_on), assigned_to, member_ids[].

Status always starts at planned. Without projects.assign, assigned_to / member_ids are ignored and the creator becomes the assignee. Assignee ids are stripped from member_ids.

GET /projects/{id}

Includes contact, company, opportunity, assignee, creator, members, notes, and timeline activities. Embedded notes and timeline/domain activities are newest-first (created_at DESC, then id DESC).

PUT /projects/{id}

Partial update of content fields (title, description, soft links, dates, and — with projects.assignassigned_to / member_ids). Status changes use POST /projects/{id}/status.

DELETE /projects/{id}

Soft delete. Permission: projects.delete.

POST /projects/{id}/restore

Permission: projects.restore.

DELETE /projects/{id}/force

Permanently delete a soft-deleted project. Permission: projects.force.delete (owner/superadmin only by default).

Actions

POST /projects/{id}/assign

{ "assigned_to": number|null }

Permission: projects.assign. Detaches the new assignee from members if present.

PUT /projects/{id}/members

{ "member_ids": number[] }

Permission: projects.assign. Full sync; assignee is never stored as a member.

POST /projects/{id}/status

{ "status": "planned"|"active"|"on_hold"|"completed"|"cancelled" }

Permission: projects.update. Allowed transitions:

FromTo
plannedactive, cancelled
activeon_hold, completed, cancelled
on_holdactive, cancelled
completed / cancelled(none)

Rejects disallowed transitions with a 422 validation error on status.

POST /projects/{id}/notes

{ "body": string }

Permission: projects.update.

GET /projects/{id}/timeline

Domain timeline entries (created, updated, assigned, members_synced, status_changed, note_added, deleted, restored).

When creating or updating a task, optional project_id is validated by LinkableProject (Projects module entitled + project visible to the actor). Response embeds project (id, uuid, title, status) when loaded. Documented under Tenant Tasks.

Dashboard widgets

When Projects is entitled and the actor has projects.view, GET /dashboard may include:

idNotes
active_projectsActive-status rows + total_count; visibility-scoped
overdue_projectsOpen + ends_on before workspace today; visibility-scoped

See Tenant Dashboard.

Official documentation for the EloSync SaaS Platform.