Create a project
const url = 'https://api.hydrate.sh/v1/projects';const options = { method: 'POST', headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'}, body: '{"intent":"cli","language":"python","name":"example"}'};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}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.
Authorizations
Section titled “Authorizations”Request Bodyrequired
Section titled “Request Bodyrequired”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).
Responses
Section titled “Responses”Successful Response
object
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
object
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.
object
Example
{ "detail": "unauthenticated"}Credentials are valid but lack the scope required for this route, or the principal lacks membership in the target project.
object
object
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).
object
object
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.
object
object
Example
{ "detail": { "code": "invalid_name" }}Per-bucket rate limit exceeded. The response carries Retry-After and the standard X-RateLimit-* headers (Limit / Remaining / Reset).
object
Example
{ "detail": "rate_limited"}