Skip to content

Create a project

POST
/v1/projects
curl --request POST \
--url https://api.hydrate.sh/v1/projects \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '{ "intent": "cli", "language": "python", "name": "example" }'

Create a new project owned by the caller. Creating a project also seeds its protected main branch in the same transaction, so the returned main_branch can be forked immediately (via POST /v1/projects/{project_id}/branches) with no second round-trip. The name must be unique among your active projects (case-insensitive); a collision returns 409 name_taken. Requires the graph:write scope.

Media typeapplication/json
V1CreateProjectBody

Body for POST /v1/projects. Only name is required; language and intent default server-side to python/cli (mirrored by the CLI hydrate new defaults).

object
intent
Any of:
string
<= 40 characters
language
Any of:
string
<= 40 characters
name
required
Name

Project name. Unique per-user, case-insensitive.

string
>= 1 characters <= 200 characters

Successful Response

Media typeapplication/json
ProjectCreateResponse
object
main_branch
required
MainBranchRef

The seeded main branch as returned by project-create.

Deliberately narrower than BranchMeta: create returns only what the client can’t mint locally and needs for its next call. Pinning the real shape (not BranchMeta) keeps the generated SDK honest.

object
id
required
Id
string format: uuid
version
required
Version
integer
project
required
ProjectOut
object
archived
required
Archived
boolean
created_at
required
Created At
string
h2o_schema_version
required
H2O Schema Version
integer
id
required
Id
string format: uuid
intent
required
Any of:
string
language
required
Any of:
string
last_opened_at
required
Any of:
string
name
required
Name
string
updated_at
required
Updated At
string
version
required
Version
string
Examplegenerated
{
"main_branch": {
"id": "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0",
"version": 1
},
"project": {
"archived": true,
"created_at": "example",
"h2o_schema_version": 1,
"id": "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0",
"intent": "example",
"language": "example",
"last_opened_at": "example",
"name": "example",
"updated_at": "example"
},
"version": "example"
}

No credentials, malformed credentials, or revoked credentials. The envelope is leak-parity (same shape across all 401 paths) so an attacker cannot distinguish revoked vs. unknown via the body.

Media typeapplication/json
object
detail
required
string
Example
{
"detail": "unauthenticated"
}

Credentials are valid but lack the scope required for this route, or the principal lacks membership in the target project.

Media typeapplication/json
object
detail
object
code
string
message
string
Examplegenerated
{
"detail": {
"code": "example",
"message": "example"
}
}

The project could not be created because it conflicts with existing state. name_taken — an active project of yours already uses this name (case-insensitive); pick another. project_limit_reached — you are at the per-user project cap, which counts ARCHIVED projects too; delete a project to free a slot (archiving does not).

Media typeapplication/json
object
detail
object
code
required
string
Allowed values: name_taken project_limit_reached
message
required
string
Example
{
"detail": {
"code": "name_taken"
}
}

A field in the request body is not acceptable. invalid_name — the name is blank after trimming. unsupported_language / unsupported_intent — the value is outside the server’s allowlist. NOTE: this envelope is {detail: {code, message}}, NOT FastAPI’s HTTPValidationError.

Media typeapplication/json
object
detail
object
code
required
string
Allowed values: invalid_name unsupported_language unsupported_intent
message
required
string
Example
{
"detail": {
"code": "invalid_name"
}
}

Per-bucket rate limit exceeded. The response carries Retry-After and the standard X-RateLimit-* headers (Limit / Remaining / Reset).

Media typeapplication/json
object
detail
string
Example
{
"detail": "rate_limited"
}
Retry-After
integer
X-RateLimit-Limit
integer
X-RateLimit-Remaining
integer
X-RateLimit-Reset
integer