Skip to content

Rename or archive a project

PATCH
/v1/projects/{project_id}
curl --request PATCH \
--url https://api.hydrate.sh/v1/projects/2489E9AD-2EE2-8E00-8EC9-32D5F69181C0 \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '{ "archived": true, "name": "example" }'

Rename a project you own, archive it, or restore it. At least one of name or archived must be present; an empty body is rejected with 422 no_fields rather than reporting success for a request that changed nothing.

Archiving is the non-destructive alternative to deletion: the project leaves GET /v1/projects but remains addressable by id and can be restored. It does not free a slot against your project cap — only deletion does.

Requires graph:write — deliberately NOT a scope of its own, unlike project:delete. That scope exists because deletion is irreversible; both edits here round-trip, so an authoring key holding them cannot destroy anything it cannot also put back. The consequence is that every existing graph:write key gains rename and archive when this ships, with no re-mint.

Only the owner may modify a project; a caller who can see it but does not own it gets the same 404 a non-existent project gets.

project_id
required
Project Id

The project to modify.

string format: uuid

The project to modify.

Media typeapplication/json
V1PatchProjectBody

Body for PATCH /v1/projects/{project_id}.

Deliberately narrower than the legacy session router’s patch body, which also carries language, intent and layout_mode. Those are creation-time metadata on the agent surface; widening this later is additive, whereas shipping fields the CLI has no verb for is not.

object
archived
Any of:
boolean
name
Any of:
string
>= 1 characters <= 200 characters
Examplegenerated
{
"archived": true,
"name": "example"
}

Successful Response

Media typeapplication/json
ProjectPatchResponse

Rename/archive returns the project alone.

No main_branch, unlike create: the branch is not affected by either edit, and echoing it would imply otherwise.

object
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
{
"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"
}
}

Resource not found OR not accessible to this principal. Leak parity: the response is identical in both cases so an attacker cannot enumerate resources via 404-vs-403 timing.

Media typeapplication/json
object
detail
object
code
string
message
string
Example
{
"detail": {
"code": "not_found"
}
}

Validation Error

Media typeapplication/json
HTTPValidationError
object
detail
Detail
Array<object>
ValidationError
object
ctx
Context
object
input
Input
loc
required
Location
Array
msg
required
Message
string
type
required
Error Type
string
Examplegenerated
{
"detail": [
{
"ctx": {},
"input": "example",
"loc": [
"example"
],
"msg": "example",
"type": "example"
}
]
}

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