Projects API

Project API access follows the current Keito permissions and active project assignments of the user bound to the credential.

Visibility and Permissions

Identity Read Create Update, archive, restore Delete
Owner or Administrator All workspace projects Yes Yes Yes
Manager with Edit projects Actively assigned projects Yes Only assigned projects they manage No
Other active internal user Actively assigned projects No No No
Personal read-only sync key Assigned project list and item reads No No No

Changing a role, Manager permission, active assignment, or project-manager status takes effect on the next request. A missing, cross-workspace, or unassigned project returns 404, so callers cannot use the API to discover inaccessible records.

Rates, fees, budgets, task budgets, and internal costs are omitted unless the bound user has the corresponding financial visibility in Keito. Collection, item, and mutation responses use the same redaction.

List Projects

GET /api/v2/projects

Supported query parameters are is_active, client_id, updated_since, owner_id, page, and per_page. Personal read-only sync keys support is_active, owner_id, page, and per_page only.

curl "https://app.keito.ai/api/v2/projects?is_active=true&per_page=100" \
  -H "Authorization: Bearer $KEITO_API_KEY" \
  -H "Keito-Account-Id: $KEITO_ACCOUNT_ID"

Get a Project

GET /api/v2/projects/{id}

A successful item read returns an ETag for the exact permission-filtered representation. Financial-visibility changes therefore change the validator.

Create a Project

POST /api/v2/projects

client_id and name are required. You may also set owner_id, code, notes, dates, task_ids, and consistent billing and budget settings. Commercial properties require the same elevated billable-rate permission as the Keito interface.

curl -X POST "https://app.keito.ai/api/v2/projects" \
  -H "Authorization: Bearer $KEITO_API_KEY" \
  -H "Keito-Account-Id: $KEITO_ACCOUNT_ID" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: project-create-001" \
  --data '{"client_id":"client_id","name":"Example project","code":"EXAMPLE"}'

Omit task_ids to assign workspace default tasks, or pass an empty array to assign none. Cross-workspace or inactive relationship IDs are rejected. A successful create returns 201 Created, Location, and ETag.

Update, Archive, or Restore

PATCH /api/v2/projects/{id}

Owners and Administrators may update any visible project. A Manager needs Edit projects and must currently manage that project. Use is_active: false to archive and is_active: true to restore.

curl -X PATCH "https://app.keito.ai/api/v2/projects/$PROJECT_ID" \
  -H "Authorization: Bearer $KEITO_API_KEY" \
  -H "Keito-Account-Id: $KEITO_ACCOUNT_ID" \
  -H "Content-Type: application/json" \
  -H 'If-Match: "etag-from-the-latest-read"' \
  -H "Idempotency-Key: project-update-001" \
  --data '{"name":"Updated project"}'

If-Match is optional for PATCH but strongly recommended. A stale value returns 412 Precondition Failed.

Permanently Delete a Project

DELETE /api/v2/projects/{id}

Permanent deletion is Owner/Administrator-only. The project must already be archived and the request must include the latest If-Match; missing or stale preconditions return 428 or 412. Keito removes project-bound time, expenses, assignments, tasks, and integration mappings while preserving historical invoice lines. Dependencies that cannot be preserved return 409.

Use a disposable project, archive it first, and confirm invoice-history requirements before testing deletion. Deletion cannot be undone.

Tasks and Project Task Budgets

Tasks are reusable across a workspace, while their budgets belong to a task’s assignment to a project. A workspace-global GET /api/v2/tasks omits budget. To return the active project-task assignment budget, pass project_id:

curl "https://app.keito.ai/api/v2/tasks?project_id=$PROJECT_ID&is_active=true" \
  -H "Authorization: Bearer $KEITO_API_KEY" \
  -H "Keito-Account-Id: $KEITO_ACCOUNT_ID"

Use project context when choosing a task for a time entry: Keito validates that the task is actively assigned to the selected project and may apply member-specific task restrictions. Personal read-only sync keys cannot call /api/v2/tasks; their fixed allowlist provides project directory reads only.

budget can be 0 or null. Keito omits it when there is no project context, the assignment is inactive or missing, or the caller cannot view that project’s budget. Nested project tasks follow the same rule. Detect support through project-task-budgets in X-Keito-Features.

Safe Retries and Request Rules

Mutation requests may include an Idempotency-Key containing 8–255 letters, numbers, dots, underscores, or hyphens. The same key, request, precondition, and authorization context replays the stored response for 24 hours. Reusing a key for different input, after a permission change, or while the original request is still running returns 409.

Bodies must be uncompressed UTF-8 application/json, are limited to 128 KiB, and use strict schemas. Unknown properties, empty updates, inconsistent billing settings, invalid date ranges, and out-of-range amounts are rejected. Responses are private, no-store.