---
title: "Create a project"
method: POST
path: "/v1/projects"
tags: ["projects"]
---

# Create a project

`POST /v1/projects`

## Request

- Base URL: `https://api.hyperresearch.ai`
- URL: `https://api.hyperresearch.ai/v1/projects`
- Auth: one of:
  - HTTP bearer
  - API key in cookie `hr_session`

Names are trimmed and unique per workspace (exact, case-sensitive, archived projects included); a duplicate is a 409 `project_name_taken`. A new project starts `active` with no runs. An `Idempotency-Key` replays the first 201 for 24 hours; the same key with a different body is a 409 `idempotency_key_reuse`.

## Headers

- `idempotency-key` string

## Request body

- CreateProjectBody
  - `name` string, required
  - `description` string

## Response `201`

Project created

- Project
  - `id` string, required
  - `name` string, required
  - `description` string, nullable, required
  - `status` 'active' | 'archived', required
  - `created_at` string, required
  - `updated_at` string, required
  - `counts` ProjectCounts, required
    - `runs` integer, required: Runs filed under this project.
    - `reports` integer, required: Those runs that finished (`done`).
    - `sources` integer, required: Sources the runs filed here KEPT, summed: `SUM(runs.sources_fetched)` over the runs filed here, under the same definition as `runs.sources_fetched` on a run (a failed attempt is not a source). Computed in the same statement as `runs` and `reports`, so the list and the detail always agree; a run that has recorded no count yet contributes 0.
  - `latest_run` ProjectLatestRun, nullable, required
    - `id` string, required
    - `status` string, required
    - `tier` string, required
    - `created_at` string, required
    - `started_at` string, nullable, required: When the run actually began, as opposed to when it was queued.
    - `finished_at` string, nullable, required: When the run ENDED, null while it is still going. The project header says "latest finished N ago" and was printing `created_at` — the moment the run was launched — so a run that finished three minutes ago read as nineteen minutes ago (E2E7-09). Read this for that sentence.
    - `duration_ms` integer, nullable, required: Wall time of the run; the same number `GET /v1/runs` and `GET /v1/runs/{id}` serve.
    - `query_preview` string, nullable, required: Server-derived excerpt of that run’s canonical question.

## Other responses

- `400`: Invalid request
- `401`: Authentication failed
- `403`: Insufficient scope or plan
- `404`: Not found
- `409`: A project with this name already exists in the workspace, or the Idempotency-Key was reused with a different body
- `429`: Rate limited or over quota
- `500`: Internal error

---

[API](https://skmtc.dev/hyperresearch/apis/hyperresearch-cloud-api.md) · [All operations](https://skmtc.dev/hyperresearch/apis/hyperresearch-cloud-api/llms.txt) · [OpenAPI document](https://skmtc.dev/hyperresearch/apis/hyperresearch-cloud-api/revisions/726ef831ebf4?raw)
