Overview

ProjectLayer is a project management tool built for development teams. It provides kanban boards, task tracking with filtering, milestones, labels, a backlog with direct SupportLayer integration, reports, email notifications, a full activity audit log, and team management with role-based permissions.

Quick start

  1. Create an accountRegister here. Your first member seat is free.
  2. Verify your email — Check your inbox for a verification link and click it to activate your account.
  3. Create a project — Give it a name and a prefix (e.g. API). This prefix is used in task keys like API-42.
  4. Add tasks — Create tasks with titles, descriptions, priorities, assignees, due dates, and labels.
  5. Use the board — Every project gets a default Kanban board with To Do, In Progress, and Done columns. Move tasks between columns.
  6. Create milestones — Set deadlines and track progress toward releases or goals.
  7. Invite your team — Go to Team Members in the admin sidebar and send email invitations with a chosen role.

Key concepts

  • Organization — Your workspace. All projects, members, and settings belong to an organization. A user can belong to multiple organizations.
  • Project — Groups related tasks, boards, milestones, labels, and backlog items. Each project has a unique prefix for task keys.
  • Task — An individual work item with a key (e.g. API-42), status, priority, assignee, due date, labels, and comments.
  • Board — A Kanban view with ordered columns. Tasks are placed in columns and moved between them.
  • Milestone — A target date or goal. Assign tasks to a milestone to track progress.
  • Label — A color-coded tag for categorizing tasks within a project.
  • Backlog — A holding area for items that haven't been promoted to tasks yet. Items can arrive from the API (e.g. SupportLayer) or be converted to tasks.
  • Access group — A role that defines what a member can do. Default groups: Administrator, Member, Viewer.

Projects

Projects are the top-level container for all work. Each project has:

  • Name and prefix — The prefix (e.g. WEB) is used in task keys like WEB-15.
  • Description — Optional project description visible on the overview page.
  • Owner — An optional team member who owns the project.
  • Status — Active, Completed, or Archived. Archived projects are hidden from the main list.

From a project's overview page, you can navigate to Tasks, Board, Backlog, Milestones, and Labels using the tabbed sub-navigation.

Projects can be edited or archived from the project overview page.

Tasks & filtering

Tasks are the core work items. Each task includes:

  • Task key — Auto-generated from the project prefix (e.g. API-42).
  • Status — Open, In Progress, Done, or Closed. Change inline on the task detail page.
  • Priority — Low, Medium, High, or Critical.
  • Assignee — A team member responsible for the task. Change inline.
  • Due date — Optional deadline. Set at creation or change inline.
  • Labels — Color-coded tags from the project's label set.
  • Description — Detailed information about the work.
  • Comments — Threaded discussion on each task.

Filtering tasks

The task list includes a filter toolbar. You can filter by:

  • Text search — Matches against task titles.
  • Status — Show only tasks in a specific status.
  • Priority — Show only tasks of a specific priority.
  • Assignee — Show tasks assigned to a specific member, or show unassigned tasks.

Filters are applied via URL query parameters, so filtered views can be bookmarked or shared.

Deleting tasks

Tasks can be permanently deleted from the task detail page. This requires the task.delete permission.

Kanban boards

Every project comes with a default Kanban board containing three columns: To Do, In Progress, and Done.

Tasks can be moved between columns using the move buttons on each task card. Moving a task to a "complete" column (like Done) automatically sets its status to Done.

Tasks not assigned to any column appear in a separate "No Column" section on the board, with buttons to move them into any column.

Milestones

Milestones represent releases, sprints, or goals with optional due dates.

  • Create milestones from the Milestones tab within a project.
  • Assign tasks to milestones to track progress.
  • Open or close milestones to mark them as complete.
  • The milestone list shows the number of associated tasks.

Labels

Labels are color-coded tags for categorizing tasks within a project.

  • Create labels from the Labels tab — pick a name and color.
  • Assign labels to tasks using checkboxes on the task detail page.
  • Labels appear as colored pills on both the task list and task detail views.

Backlog

The backlog is a holding area for work items that haven't been promoted to full tasks.

  • Items can arrive via the Backlog API (e.g. from SupportLayer).
  • Each item shows its source, priority, and a link back to the originating ticket.
  • Accept — Mark as approved for future work.
  • Reject — Decline the item.
  • Convert to task — Create a full task from the backlog item, with the title, description, and priority carried over.

Reports

The Reports page (available to admins) provides an overview of your organization's work:

  • Summary stats — Total tasks, overdue count, active tasks, completed tasks.
  • Tasks by status — Bar chart showing the distribution of tasks across statuses.
  • Tasks by priority — Bar chart showing priority distribution.
  • Tasks by project — Count of tasks per project.
  • Team workload — Bar chart showing how many open tasks each team member has.

Email notifications

ProjectLayer sends email notifications for key task events. Each user can control their preferences from the Profile & Notifications page.

EventWho is notifiedPreference
Task assigned to youThe new assigneeWhen a task is assigned to me
New comment on taskAssignee and reporter (excluding the comment author)When someone comments on my task
Task status changedAssignee and reporterWhen a task status changes

All notifications include a direct link to the task.

Activity log

Every task has a full activity log visible on its detail page, below the comments section. The log records:

  • Task creation (including creation from backlog items)
  • Status changes (with old and new values)
  • Priority changes
  • Assignee changes
  • Due date changes
  • Comments added

Each entry shows the actor, the action, and the timestamp.

Team management

Manage your organization's members from Admin → Team Members.

  • View members — See name, email, role, and status for every member.
  • Change roles — Use the role dropdown on any member to change their access group instantly.
  • Suspend members — Temporarily revoke access. Suspended members cannot log in to the organization.
  • Reactivate members — Restore access for a suspended member.

You cannot suspend the last administrator — at least one admin must remain active.

Inviting members

Invite new members from the Team Members page:

  1. Enter the invitee's email address.
  2. Select a role (Administrator, Member, or Viewer).
  3. Click Send invite.

The invitee receives an email with a link to join. If they already have a ProjectLayer account, they are automatically added to your organization. If not, they are prompted to create an account and are added upon completion.

Invitations expire after 7 days.

Roles & permissions

Every member belongs to one access group within an organization. Three default groups are created with each organization:

RolePermissions
Administrator All permissions — full control over projects, tasks, boards, backlog, settings, and user management.
Member View and create projects; full task management (create, edit, assign); board and backlog management. Cannot access settings or manage users.
Viewer View projects and tasks only. Cannot create, edit, or assign.

Custom access groups can be created from Admin → Access Groups with any combination of permissions:

PermissionDescription
project.viewView projects
project.createCreate new projects
project.editEdit project details, manage milestones and labels
project.deleteDelete projects
task.view_ownView tasks assigned to you
task.view_allView all tasks in a project
task.createCreate new tasks
task.editEdit task details, move on board
task.assignAssign tasks to team members
task.deleteDelete tasks
board.manageManage board columns
backlog.manageAccept, reject, and convert backlog items
settings.manageAccess admin settings, branding, API keys, reports
user.manageInvite, suspend, and manage team members

Registration

Create an account at the registration page. You'll provide your name, email, password, and organization name. A new organization is created automatically with you as the administrator.

Three default access groups (Administrator, Member, Viewer) are provisioned with your organization.

Email verification

After registration, you'll receive a verification email. Click the link to verify your email address. You must verify before you can sign in.

If you didn't receive the email, use the resend verification page.

Password reset

If you've forgotten your password:

  1. Go to Forgot password from the sign-in page.
  2. Enter your email address.
  3. Check your inbox for a reset link (valid for 1 hour).
  4. Click the link and set a new password (minimum 8 characters).

Branding

Customize the portal appearance from Admin → Branding:

  • Primary colour — Used for the sidebar, buttons, and links. Enter a hex value (e.g. #3d2f7c).
  • Accent colour — Used for highlights and secondary actions.

Leave fields empty to use ProjectLayer's default colours. Changes take effect immediately for all members.

Billing

ProjectLayer uses simple per-seat pricing:

  • Free plan — 1 member seat included. No credit card required.
  • Pro plan — 1 free seat + additional paid seats at $12 USD / £10 GBP / €12 EUR per month.

All features are available on both plans. There are no feature gates. Administrators and viewers do not count toward paid seat limits.

Manage your subscription from Account & Plan. Pro plan customers can manage billing, change payment methods, and adjust seat counts via the Stripe billing portal.

API Authentication

The ProjectLayer API uses Bearer token authentication. Generate API keys from Settings → API Keys in the portal. Download the OpenAPI spec for a complete, machine-readable description of every endpoint.

Include the key in the Authorization header:

Authorization: Bearer pl_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

API keys are scoped to your organization. All requests made with a key will only see and modify data within that organization.

Scopes

Each key is created with one of two access levels:

ScopeCan do
Read & writeAll GET requests, plus POST/PATCH/PUT/DELETE
Read onlyOnly GET/HEAD/OPTIONS requests

A request that exceeds a key's scope returns 403 Forbidden:

{
  "error": {
    "code": "insufficient_scope",
    "message": "This API key lacks the 'write' scope."
  }
}

Keys created before scopes existed have no scope recorded, which is treated as full (read & write) access.

Base URL

https://your-projectlayer-domain.com/api/v1/

Pagination

Every list endpoint accepts ?page (default 1) and ?per_page (default 25, clamped to 1–100) and returns a meta block alongside data:

{
  "data": [ ... ],
  "meta": { "page": 1, "per_page": 25, "total": 137, "total_pages": 6 }
}

Error responses

Errors return a JSON object with an error field:

{
  "error": {
    "code": "authentication_failed",
    "message": "Invalid or revoked API key."
  }
}

API — Projects

List projects

GET /api/v1/projects

Returns a page of active projects in your organization (see Pagination).

Response:

{
  "data": [
    {
      "id": 1,
      "name": "API Platform",
      "slug": "api-platform",
      "prefix": "API",
      "status": "active"
    }
  ],
  "meta": { "page": 1, "per_page": 25, "total": 1, "total_pages": 1 }
}

API — Tasks

List tasks

GET /api/v1/tasks

Returns a page of tasks in your organization, most recently updated first (see Pagination).

Query parameterTypeDescription
has_planbooleanWhen 1 (or true), returns only tasks that have a Claude build plan, most recently planned first.
project_idintegerRestrict to a single project. Can be combined with has_plan. An unknown ID returns 404.
page, per_pageintegerSee Pagination.

Response:

{
  "data": [
    {
      "id": 42,
      "task_key": "API-42",
      "title": "Add CSV export",
      "project_id": 1,
      "status": "in_progress",
      "priority": "high",
      "has_plan": true,
      "plan_updated_at": "2026-07-05T13:55:00+00:00"
    }
  ],
  "meta": { "page": 1, "per_page": 25, "total": 1, "total_pages": 1 }
}

Get a task

GET /api/v1/tasks/{id}

Returns a single task, including its description and full Claude build plan. claude_plan and plan_updated_at are null when no plan has been generated. Returns 404 if the task is not found in your organization.

Response:

{
  "id": 42,
  "task_key": "API-42",
  "title": "Add CSV export",
  "project_id": 1,
  "status": "in_progress",
  "priority": "high",
  "has_plan": true,
  "plan_updated_at": "2026-07-05T13:55:00+00:00",
  "description": "Export the report as CSV.",
  "claude_plan": "1. Add the export endpoint...\n2. Stream rows...\n3. Verify with a functional test."
}

Claude build plans: the claude_plan field holds the development plan generated by the "Plan with Claude" button on a task. Use GET /api/v1/tasks?has_plan=1 to discover which tasks already have a plan, then fetch each one to read it.

Update a task's status

PATCH /api/v1/tasks/{id}/status

Updates the status of a task — for example, to mark it in_progress when work begins or done when it is completed. Automation such as a Claude Code skill can call this to reflect build progress. POST is also accepted for clients that cannot send PATCH.

Request body:

{
  "status": "in_progress"
}
FieldTypeRequiredDescription
statusstringYesopen, in_progress, done, or closed.

Setting the status to done or closed stamps the task's completion time; moving it back to open or in_progress clears it. The change is recorded in the task's activity log and notifies the assignee and reporter. An unknown status returns 400; a task not found in your organization returns 404.

Response: the updated task (same shape as Get a task), for example:

{
  "id": 42,
  "task_key": "API-42",
  "title": "Add CSV export",
  "project_id": 1,
  "status": "in_progress",
  "priority": "high",
  "has_plan": true,
  "plan_updated_at": "2026-07-05T13:55:00+00:00",
  "description": "Export the report as CSV.",
  "claude_plan": "1. Add the export endpoint..."
}

Create a task

POST /api/v1/tasks

Requires the write scope. Allocates the next task number for the project, the same way the "New task" form does.

FieldTypeRequiredDescription
project_idintegerYesTarget project ID. An unknown ID returns 404.
titlestringYesTask title
descriptionstringNoDescription
prioritystringNolow, medium, high, or critical. Default: medium
assignee_idintegerNoMust be an active member of your organization
milestone_idintegerNoMust belong to the same project
claude_planstringNoBuild plan in Markdown. Sets plan_updated_at when provided.

Response (201 Created): the created task (same shape as Get a task). Invalid input returns 400.

Update a task

PATCH /api/v1/tasks/{id}

Requires the write scope. Partial update: only fields present in the body are changed. Accepts title, description, priority, status, assignee_id, milestone_id, and claude_plan (same rules as create). Setting assignee_id or milestone_id to null clears it. Writing claude_plan sets the task's build plan (Markdown), stamps plan_updated_at, and clears any in-progress or errored planning state; sending null or an empty string clears the plan.

Response: the updated task. Invalid input returns 400; not found in your organization returns 404.

Delete a task

DELETE /api/v1/tasks/{id}

Requires the write scope. Returns 204 No Content on success, 404 if not found in your organization.

API — Comments

List a task's comments

GET /api/v1/tasks/{taskId}/comments

Returns the task's comments, oldest first, paginated (see below). 404 if the task isn't found in your organization.

Response:

{
  "data": [
    {
      "id": 9,
      "task_id": 42,
      "author": "Ada Lovelace",
      "author_type": "user",
      "body": "Looks good to me.",
      "created_at": "2026-07-05T09:12:00+00:00"
    }
  ],
  "meta": { "page": 1, "per_page": 25, "total": 1, "total_pages": 1 }
}

Create a comment

POST /api/v1/tasks/{taskId}/comments

Requires the write scope. body is required and is HTML-sanitized the same way the web comment form is (scripts and event handler attributes are stripped). A body that's empty after sanitizing returns 400.

Response (201 Created): the created comment (same shape as above, a single object rather than a list).

API — Milestones

List milestones

GET /api/v1/milestones?project_id=1
GET /api/v1/projects/{projectId}/milestones

project_id is optional on the first form; both forms return the same shape, paginated.

Response:

{
  "data": [
    {
      "id": 3,
      "project_id": 1,
      "name": "v1.0",
      "description": null,
      "due_date": "2026-08-01",
      "status": "open"
    }
  ],
  "meta": { "page": 1, "per_page": 25, "total": 1, "total_pages": 1 }
}

Get a milestone

GET /api/v1/milestones/{id}

Response: a single milestone (same shape as above). 404 if not found in your organization.

Create a milestone

POST /api/v1/milestones

Requires the write scope.

FieldTypeRequiredDescription
project_idintegerYesTarget project ID
namestringYesMilestone name
descriptionstringNoDescription
due_datestringNoYYYY-MM-DD
statusstringNoopen or closed. Default: open

Response (201 Created): the created milestone.

Update / delete a milestone

PATCH /api/v1/milestones/{id}
DELETE /api/v1/milestones/{id}

Both require the write scope. PATCH applies only the fields present in the body and returns the updated milestone. DELETE returns 204 No Content.

API — Backlog

Create a backlog item

POST /api/v1/backlog

Request body:

{
  "project_id": 1,
  "title": "Customer reports broken CSV export",
  "description": "Details from the support ticket...",
  "priority": "high",
  "source_service": "supportlayer",
  "source_ticket_id": 1842,
  "source_ticket_url": "https://support.example.com/portal/tickets/1842"
}
FieldTypeRequiredDescription
project_idintegerYesTarget project ID
titlestringYesBacklog item title
descriptionstringNoDetailed description
prioritystringNolow, medium, high, or critical. Default: medium
source_servicestringNoSource system identifier. Default: supportlayer
source_ticket_idintegerNoExternal ticket ID (used for deduplication)
source_ticket_urlstringNoURL back to the source ticket

Response (201 Created):

{
  "id": 15,
  "status": "pending"
}

Duplicate detection: If a backlog item already exists for the same source_service + source_ticket_id, the API returns 409 Conflict with the existing item's ID and status.

Get a backlog item

GET /api/v1/backlog/{id}

Response:

{
  "id": 15,
  "title": "Customer reports broken CSV export",
  "status": "pending",
  "priority": "high",
  "project_id": 1,
  "source_service": "supportlayer",
  "source_ticket_id": 1842,
  "converted_task_id": null,
  "created_at": "2026-04-10T14:30:00+00:00"
}

List backlog items

GET /api/v1/backlog?project_id=1&status=pending

Both query parameters are optional. Returns items newest first, paginated (see below).

Claude Code

Plan a task with Claude, then let Claude Code build it. Press Plan with Claude on a task and Claude — reading your connected GitHub repo for context — writes a build plan onto the task. Claude Code, running in your own terminal, then discovers planned tasks over the REST API, reads the plan, implements the work, and updates the task's status as it goes.

Install the plugin

The skills that drive this loop are published as a Claude Code plugin marketplace at github.com/XegenLtd/Claude-Skills. Add it from inside Claude Code:

/plugin marketplace add XegenLtd/Claude-Skills

Then install the ProjectLayer skills from that marketplace and authenticate with a ProjectLayer API token (see API Authentication).

How the loop uses the API

Enable "Plan with Claude" first under Settings › AI / Claude by adding your own Anthropic API key (and an optional GitHub token for repo-aware plans).

SupportLayer Integration

ProjectLayer integrates with SupportLayer to convert support tickets into backlog items automatically.

How it works

  1. Generate an API key in ProjectLayer (Settings → API Keys).
  2. Configure the key in your SupportLayer instance under Integrations.
  3. When a support agent clicks "Send to ProjectLayer" on a ticket, SupportLayer calls the POST /api/v1/backlog endpoint.
  4. The ticket appears in your ProjectLayer backlog with a link back to the original ticket.
  5. Your team reviews the backlog and converts accepted items into tasks.

Backlog statuses

StatusMeaning
pendingNewly arrived, awaiting review
acceptedApproved by the team, not yet a task
rejectedDeclined — won't be worked on
convertedPromoted to a full task (linked to the new task)

Deduplication

If SupportLayer sends the same ticket twice (same source_service + source_ticket_id), the API returns 409 Conflict instead of creating a duplicate. The response includes the existing backlog item's ID and current status.