Delete a working branch
const url = 'https://api.hydrate.sh/v1/branches/2489E9AD-2EE2-8E00-8EC9-32D5F69181C0?expected_version=1';const options = {method: 'DELETE', headers: {Authorization: 'Bearer <token>'}};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}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.
Authorizations
Section titled “Authorizations”Parameters
Section titled “Parameters”Path Parameters
Section titled “Path Parameters”The branch to delete.
The branch to delete.
Query Parameters
Section titled “Query Parameters”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.
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.
Responses
Section titled “Responses”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.
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"}