============ Projects API ============ Projects are the top-level organizational unit. Datasets, experiments, models, deployments, and all other resources belong to a project. .. contents:: Endpoints :local: :depth: 1 ---- List Projects ------------- .. code-block:: text GET /api/projects Return projects accessible to the authenticated user (owned or shared). **Query Parameters** .. list-table:: :header-rows: 1 :widths: 20 10 10 60 * - Parameter - Type - Default - Description * - ``limit`` - integer - 50 - Max items (1--500). * - ``offset`` - integer - 0 - Pagination offset. * - ``search`` - string - -- - Search in name and description (case-insensitive). * - ``sort_field`` - string - ``created_at`` - One of ``created_at``, ``name``, ``dataset_count``, ``model_count``, ``experiment_count``. * - ``sort_direction`` - string - ``desc`` - ``asc`` or ``desc``. **Example** .. code-block:: bash curl "$BASE_URL/api/projects?limit=10&search=fraud" \ -H "Authorization: Bearer YOUR_API_KEY" .. code-block:: python import requests resp = requests.get(f"{BASE_URL}/api/projects", headers={ "Authorization": "Bearer YOUR_API_KEY", }, params={"limit": 10, "search": "fraud"}) data = resp.json() for p in data["items"]: print(p["id"], p["name"]) **Response** ``200 OK`` .. code-block:: json { "items": [ { "id": "c3d4e5f6-a7b8-9012-cdef-345678901234", "name": "Fraud Detection v2", "description": "Credit card fraud classification", "status": "active", "dataset_count": 3, "experiment_count": 5, "model_count": 12, "created_at": "2026-02-10T09:00:00Z" } ], "total": 1, "limit": 10, "offset": 0 } ---- Create Project -------------- .. code-block:: text POST /api/projects **Request Body** .. list-table:: :header-rows: 1 :widths: 20 10 10 60 * - Field - Type - Required - Description * - ``name`` - string - Yes - Project name (must not be empty). * - ``description`` - string - No - Optional description. **Example** .. code-block:: bash curl -X POST "$BASE_URL/api/projects" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"name": "Churn Prediction", "description": "Telco customer churn"}' .. code-block:: python resp = requests.post(f"{BASE_URL}/api/projects", headers={ "Authorization": "Bearer YOUR_API_KEY", }, json={ "name": "Churn Prediction", "description": "Telco customer churn", }) project = resp.json() print("Project ID:", project["project_id"]) **Response** ``201 Created`` .. code-block:: json { "project_id": "d4e5f6a7-b8c9-0123-def4-567890123456", "project": { "id": "d4e5f6a7-b8c9-0123-def4-567890123456", "name": "Churn Prediction", "description": "Telco customer churn", "created_at": "2026-02-28T14:30:00Z" } } ---- Get Project ----------- .. code-block:: text GET /api/projects/{project_id} **Path Parameters** .. list-table:: :header-rows: 1 :widths: 20 10 70 * - Parameter - Type - Description * - ``project_id`` - UUID - Project identifier. **Example** .. code-block:: bash curl "$BASE_URL/api/projects/d4e5f6a7-b8c9-0123-def4-567890123456" \ -H "Authorization: Bearer YOUR_API_KEY" .. code-block:: python resp = requests.get( f"{BASE_URL}/api/projects/d4e5f6a7-b8c9-0123-def4-567890123456", headers={"Authorization": "Bearer YOUR_API_KEY"}, ) print(resp.json()["project"]["name"]) **Response** ``200 OK`` .. code-block:: json { "project": { "id": "d4e5f6a7-b8c9-0123-def4-567890123456", "name": "Churn Prediction", "description": "Telco customer churn", "created_at": "2026-02-28T14:30:00Z" } } ---- Update Project -------------- .. code-block:: text PUT /api/projects/{project_id} **Request Body** .. list-table:: :header-rows: 1 :widths: 20 10 10 60 * - Field - Type - Required - Description * - ``name`` - string - Yes - Updated name. * - ``description`` - string - No - Updated description. **Example** .. code-block:: bash curl -X PUT "$BASE_URL/api/projects/d4e5f6a7-b8c9-0123-def4-567890123456" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"name": "Churn Prediction v2", "description": "Updated scope"}' .. code-block:: python resp = requests.put( f"{BASE_URL}/api/projects/d4e5f6a7-b8c9-0123-def4-567890123456", headers={"Authorization": "Bearer YOUR_API_KEY"}, json={"name": "Churn Prediction v2", "description": "Updated scope"}, ) **Response** ``200 OK`` .. code-block:: json { "project": { "id": "d4e5f6a7-b8c9-0123-def4-567890123456", "name": "Churn Prediction v2", "description": "Updated scope" } } ---- Delete Project -------------- .. code-block:: text DELETE /api/projects/{project_id} Permanently delete a project. Only the project owner can perform this action. **Example** .. code-block:: bash curl -X DELETE "$BASE_URL/api/projects/d4e5f6a7-b8c9-0123-def4-567890123456" \ -H "Authorization: Bearer YOUR_API_KEY" **Response** ``200 OK`` .. code-block:: json { "ok": true } ---- List Members ------------ .. code-block:: text GET /api/projects/{project_id}/members Return the list of users who have access to this project. **Query Parameters** .. list-table:: :header-rows: 1 :widths: 20 10 10 60 * - Parameter - Type - Default - Description * - ``limit`` - integer - 50 - Max items (1--100). * - ``offset`` - integer - 0 - Pagination offset. **Example** .. code-block:: bash curl "$BASE_URL/api/projects/d4e5f6a7-b8c9-0123-def4-567890123456/members" \ -H "Authorization: Bearer YOUR_API_KEY" .. code-block:: python resp = requests.get( f"{BASE_URL}/api/projects/d4e5f6a7-b8c9-0123-def4-567890123456/members", headers={"Authorization": "Bearer YOUR_API_KEY"}, ) for member in resp.json()["items"]: print(member["email"], member["role"]) **Response** ``200 OK`` .. code-block:: json { "items": [ { "user_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "email": "alice@example.com", "name": "Alice Chen", "role": "owner", "created_at": "2026-02-10T09:00:00Z" }, { "user_id": "f6a7b8c9-0123-4567-89ab-cdef01234567", "email": "bob@example.com", "name": "Bob Smith", "role": "editor", "created_at": "2026-02-15T11:00:00Z" } ], "total": 2, "limit": 50, "offset": 0 } ---- Add Member ---------- .. code-block:: text POST /api/projects/{project_id}/members Add a user to the project or update their role. Only the project owner can manage members. You cannot assign a role higher than your own. **Request Body** .. list-table:: :header-rows: 1 :widths: 20 10 10 60 * - Field - Type - Required - Description * - ``email`` - string - Yes - Email of the user to add (must be a registered user). * - ``role`` - string - No - One of ``viewer``, ``editor``, ``admin``, ``owner``. Default: ``editor``. **Example** .. code-block:: bash curl -X POST "$BASE_URL/api/projects/d4e5f6a7-b8c9-0123-def4-567890123456/members" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"email": "bob@example.com", "role": "editor"}' .. code-block:: python resp = requests.post( f"{BASE_URL}/api/projects/d4e5f6a7-b8c9-0123-def4-567890123456/members", headers={"Authorization": "Bearer YOUR_API_KEY"}, json={"email": "bob@example.com", "role": "editor"}, ) **Response** ``201 Created`` .. code-block:: json { "member": { "user_id": "f6a7b8c9-0123-4567-89ab-cdef01234567", "email": "bob@example.com", "name": "Bob Smith", "role": "editor" } } ---- Activity Timeline ----------------- .. code-block:: text GET /api/projects/{project_id}/timeline Return a chronological list of events (datasets uploaded, experiments run) within the project. Useful for dashboards and audit trails. **Example** .. code-block:: bash curl "$BASE_URL/api/projects/d4e5f6a7-b8c9-0123-def4-567890123456/timeline" \ -H "Authorization: Bearer YOUR_API_KEY" **Response** ``200 OK`` .. code-block:: json { "project_id": "d4e5f6a7-b8c9-0123-def4-567890123456", "events": [ { "id": "e5f6a7b8-c9d0-1234-5678-90abcdef1234", "type": "dataset", "name": "transactions.csv", "timestamp": "2026-02-12T08:00:00Z", "rows": 50000, "columns": 15 }, { "id": "f6a7b8c9-d0e1-2345-6789-0abcdef12345", "type": "experiment", "name": "AutoML Run 1", "timestamp": "2026-02-12T10:30:00Z", "status": "completed", "target_column": "is_fraud", "problem_type": "classification", "best_model_type": "GBM", "duration": 342 } ] } ---- Export Project -------------- .. code-block:: text GET /api/projects/{project_id}/export Download the entire project as a ZIP archive containing a ``manifest.json`` and all associated artifacts (datasets, model binaries, reports). **Example** .. code-block:: bash curl -o project_export.zip \ "$BASE_URL/api/projects/d4e5f6a7-b8c9-0123-def4-567890123456/export" \ -H "Authorization: Bearer YOUR_API_KEY" .. code-block:: python resp = requests.get( f"{BASE_URL}/api/projects/d4e5f6a7-b8c9-0123-def4-567890123456/export", headers={"Authorization": "Bearer YOUR_API_KEY"}, ) with open("project_export.zip", "wb") as f: f.write(resp.content) **Response** ``200 OK`` Returns a binary ZIP file with ``Content-Type: application/zip``. ---- .. seealso:: - :doc:`datasets` -- Uploading data to a project. - :doc:`experiments` -- Running AutoML within a project.