# Projects

> A project hangs off a workspace and is what campaigns, mailboxes, and inbox data attach to via X-Project-Id. Each workspace has exactly one project. Unlike…

Source: https://warmerly.com/docs/workspaces/projects

A project hangs off a workspace and is what campaigns, mailboxes, and inbox data attach to via `X-Project-Id`. Each workspace has exactly one project. Unlike the workspace/member endpoints above, listing and creating projects operates on your **active workspace** rather than a workspace ID in the URL: the one named in `X-Workspace-Id` if you belong to it, otherwise your own workspace. `GET /projects` also accepts a `workspaceId` query parameter to list another workspace you belong to (a workspace you are not a member of returns `403 forbidden`).

## List projects

```text
GET /projects
```

```json
{
  "projects": [
    {
      "id": "2b6e1c3d-...",
      "name": "Default",
      "slug": "default",
      "description": null,
      "color": null,
      "icon": null,
      "createdAt": "2026-01-10T12:00:00.000Z",
      "campaignCount": 3,
      "accountCount": 5
    }
  ]
}
```

If your active workspace has no projects yet, a default one is created automatically before the list is returned, so this endpoint never returns an empty array.

## Create a project

```text
POST /projects
```

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `name` | string | Yes | Project name, at least 1 character. |
| `slug` | string | Yes | Lowercase letters, numbers, and hyphens only (`^[a-z0-9-]+$`). A random suffix is appended automatically if the slug is already taken. |
| `description` | string | No | Up to 2000 characters. |
| `color` | string | No | Up to 32 characters. |
| `icon` | string | No | Up to 64 characters. |
| `defaultTimezone` | string | No | Up to 64 characters. |

```bash
curl https://app.warmerly.com/api/v1/projects \
  -X POST \
  -H "X-Api-Key: wmv_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{ "name": "Q3 Outbound", "slug": "q3-outbound" }'
```

```json
{
  "project": {
    "id": "9d4f2a11-...",
    "name": "Q3 Outbound",
    "slug": "q3-outbound",
    "workspaceId": "8f14e45f-ceea-4c6a-8c8d-6b1a5b5c9c1a",
    "userId": "3c2b1a09-...",
    "description": null,
    "color": null,
    "icon": null,
    "defaultTimezone": null,
    "createdAt": "2026-07-01T09:00:00.000Z"
  }
}
```

`userId` is the user who created the project. `201 Created` on success. Returns `409 conflict` if the active workspace already has a project, a workspace can only ever have one.

## Get a project

```text
GET /projects/{id}
```

Returns the project. Requires membership in the project's workspace (`403 forbidden` otherwise, `404 not_found` if the project does not exist).

```json
{
  "project": {
    "id": "9d4f2a11-...",
    "name": "Q3 Outbound",
    "slug": "q3-outbound",
    "workspaceId": "8f14e45f-ceea-4c6a-8c8d-6b1a5b5c9c1a",
    "userId": "3c2b1a09-...",
    "description": null,
    "color": null,
    "icon": null,
    "defaultTimezone": null,
    "createdAt": "2026-07-01T09:00:00.000Z"
  }
}
```

## Project stats

```text
GET /projects/{id}/stats
```

A rollup for one project: what the dashboard's project switcher shows.

```json
{
  "project": { "id": "…", "name": "SaaS Outreach", "slug": "saas-outreach-05adc35c", "workspaceId": "…", "userId": "…" },
  "campaigns": { "total": 3, "active": 2 },
  "accounts": { "total": 12 },
  "leads": { "total": 145 },
  "emails": { "sent": 300, "replied": 17, "replyRate": 5.7 }
}
```

Requires membership in the project's workspace. `accounts.total` counts every mailbox attached to the project, so it can be higher than `accountCount` from `GET /projects`, which counts only mailboxes you connected yourself. `replyRate` is a percentage with one decimal place, of real campaign sends, not a warmup figure (see [How warmup works](https://warmerly.com/docs/how-warmup-works) for why the two must not be mixed).

## More from Workspaces & Projects

- [Members](https://warmerly.com/docs/workspaces/members): Requires owner or admin.
- [Invites](https://warmerly.com/docs/workspaces/invites): Requires owner or admin.
- [Workspace housekeeping](https://warmerly.com/docs/workspaces/workspace-housekeeping): activate switches which workspace is "current" for session-based (dashboard) use and returns { "ok": true }.…
