Rename or archive a project
const url = 'https://api.hydrate.sh/v1/projects/2489E9AD-2EE2-8E00-8EC9-32D5F69181C0';const options = { method: 'PATCH', headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'}, body: '{"archived":true,"name":"example"}'};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}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.
Authorizations
Section titled “Authorizations”Parameters
Section titled “Parameters”Path Parameters
Section titled “Path Parameters”The project to modify.
The project to modify.
Request Bodyrequired
Section titled “Request Bodyrequired”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.
Examplegenerated
{ "archived": true, "name": "example"}Responses
Section titled “Responses”Successful Response
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
object
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.
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" }}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.
object
object
Example
{ "detail": { "code": "not_found" }}Validation Error
object
object
object
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).
object
Example
{ "detail": "rate_limited"}