Skip to content

Delete a working branch

DELETE
/v1/branches/{branch_id}
curl --request DELETE \
--url 'https://api.hydrate.sh/v1/branches/2489E9AD-2EE2-8E00-8EC9-32D5F69181C0?expected_version=1' \
--header 'Authorization: Bearer <token>'

Discard a working branch you own. Its structural content (nodes, ports, edges) is removed and the branch drops out of GET /v1/projects/{project_id}/branches.

The branch row and its structural_changes audit trail are kept for provenance — this is the same discard the legacy session router has always done, not a hard row delete. Re-deleting an already-discarded (or already-merged) branch is refused with 409 branch_not_active rather than silently reporting success again.

Requires expected_version — the branch version you last read, same optimistic-concurrency contract as POST .../deltas. If the branch moved underneath you (someone else pushed a delta) the request 409s version_conflict with the actual current_version rather than silently destroying content newer than what you saw.

Requires graph:write — deliberately NOT a scope of its own, unlike project:delete. See the reasoning comment above this route for the full tradeoff (reversibility, per-call cost, and listing visibility all differ from delta-erasure, but branches stay cheap/low-priority enough that a dedicated scope is deferred, not ruled out).

The protected main branch cannot be deleted: it returns 409 main_not_writable, the same refusal a structural write to main gets.

Only the branch’s owner may delete it. A caller who can see the branch but does not own it — or cannot see it at all — gets the same 404, so the response never reveals whether a branch exists.

branch_id
required
Branch Id

The branch to delete.

string format: uuid

The branch to delete.

expected_version
required
Expected Version

The branch.version the client believes is current. If it doesn’t match the server’s view at commit time, the route 409s version_conflict with the actual current_version in the detail — mirrors the deltas route’s OCC contract so a stale caller can’t silently destroy newer content.

integer

The branch.version the client believes is current. If it doesn’t match the server’s view at commit time, the route 409s version_conflict with the actual current_version in the detail — mirrors the deltas route’s OCC contract so a stale caller can’t silently destroy newer content.

Successful Response

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