Harthelm Docs
REST APIMembers

Transfer a workspace's ownership

Workspace admins (`workspace.members`). The owner's Git provider token is what the git proxy injects. A workspace whose owner left the team has `owner_id` absent and `needs_owner` set; the git proxy refuses it until it has a new owner. Making **someone else** the owner needs their consent: the answer is 202 with a pending `OwnerTransfer` that they accept or decline (`POST /owner-transfers/{transfer}/accept|decline`); until then the old owner stays the owner and the git proxy keeps using the old owner's token. A new offer replaces a pending one to another user (that one is cancelled); offering it again to the same user returns the pending one. The user must be a member of the workspace's team (409 `not-team-member`) and hold at least Editor (409 `owner-ineligible`); accepting checks that again together with their connection to the provider of the origin repository. Taking ownership oneself (`user_id` is the caller) and naming the current owner change it at once and answer 200 with the workspace; taking it cancels a pending transfer. With `promote_to` (decision 63) a Viewer or a team member without a workspace role is promoted to Editor or Admin and offered the ownership in one step.

Generated from openapi/harthelm.yaml at v1.5.0
PUT
/workspaces/{ws}/owner

Authorization

cookie__Host-harthelm_session<token>

Browser session of the UI (12 h idle, 7 days absolute). State-changing requests also need the header Harthelm-CSRF: 1 and a matching Origin.

Path Parameters

ws*integer

Numeric resource id.

Formatint64
Range1 <= value

Request Body

application/json
  1. body
user_id*ID

Numeric resource id.

Formatint64
Range1 <= value
promote_to?string

Promote-then-offer: when the offer goes to someone whose role on the workspace is below this one (a Viewer, or a team member without a workspace role), core first gives them this explicit role, then offers the ownership, in one transaction with both audit rows (workspace.role, workspace.owner_offer); if the offer fails, the role does not change either. A user who already holds the role or a higher one keeps theirs. Ignored when the answer is 200 (no offer). Absent: no promotion, and an offer to a Viewer stays 409 owner-ineligible.

Value in"editor""admin"

Response Body

The workspace; the caller is its owner now, or the named user was the owner already.

application/json
  1. response
id*ID

Numeric resource id.

Formatint64
Range1 <= value
team_id*ID

Numeric resource id.

Formatint64
Range1 <= value
name*string
plan*string

Plan id from the platform's plan list.

base_image*string

Base image id.

git?
storage_gib*integer
Range1 <= value
availability*Availability
Value in"always""on-demand"
restricted*boolean

When true, the workspace hosts are private to team members.

state*WorkspaceState
Value in"creating""cloning""running""sleeping""waking""stopped""error""deleting"
status_detail?string

Progress or error text for the current state, e.g. "Configuring storage", "Cloning repository", "Starting IDE", "Workspace is running".

urls*
dev_service?

The service behind the dev URL urls.dev: the one the route / of the entry host leads to. state is the IDE's business no more: a workspace can be running while this service sleeps. Absent for an older core.

vault_id?ID

Numeric resource id.

Formatint64
Range1 <= value
single_node?boolean

The volume is ReadWriteOnce (rwo-colocated), so every pod of the workspace runs on one node; the UI shows a "single-node workspace" badge. Absent for an older core.

idle_timeout_minutes?integer

Minutes without use before an on-demand IDE sleeps; absent: the installation's default, which GET /workspaces/{ws}/power shows as the IDE's effective timeout.

Range1 <= value <= 1440
last_archived_at?string

When the newest restorable archive of the volume was taken; absent when there is none. A workspace that never sleeps is never archived, so the UI shows the age.

Formatdate-time
restored_from?ID

Numeric resource id.

Formatint64
Range1 <= value
upgrade_pending?boolean

The IDE runs a pod template from before an upgrade of the installation (workspaces.upgradePolicy: keep) and gets the new one when it sleeps or stops; the UI shows an "upgrade pending" badge. Absent for an older core.

created_by?ID

Numeric resource id.

Formatint64
Range1 <= value
owner_id?ID

Numeric resource id.

Formatint64
Range1 <= value
needs_owner?boolean

The owner left the team or was disabled: the git proxy refuses the workspace until a workspace admin names a new owner (PUT /workspaces/{ws}/owner). Absent for an older core.

permissions?array<>

The caller's permissions on the resource; the UI shows only what they allow. Absent for an older core.

created_at*string
Formatdate-time
deleted_at?string

Set on soft-deleted workspaces.

Formatdate-time
purge_after?string

When a soft-deleted workspace is purged for good; restore works until then.

Formatdate-time
curl -X PUT 'https://console.example.com/api/v1/workspaces/1/owner' \  -H 'Content-Type: application/json' \  -d '{  "user_id": 1}'
{  "id": 1,  "team_id": 1,  "name": "string",  "plan": "string",  "base_image": "string",  "git": {    "provider": "string",    "repo": "string",    "ref": "string"  },  "storage_gib": 1,  "availability": "always",  "restricted": true,  "state": "creating",  "status_detail": "string",  "urls": {    "ide": "string",    "dev": "string"  },  "dev_service": {    "name": "string",    "state": "running",    "wake_seconds": 0,    "needs": [      "string"    ],    "failing_needs": [      "string"    ]  },  "vault_id": 1,  "single_node": true,  "idle_timeout_minutes": 1,  "last_archived_at": "2019-08-24T14:15:22Z",  "restored_from": 1,  "upgrade_pending": true,  "created_by": 1,  "owner_id": 1,  "needs_owner": true,  "permissions": [    "string"  ],  "created_at": "2019-08-24T14:15:22Z",  "deleted_at": "2019-08-24T14:15:22Z",  "purge_after": "2019-08-24T14:15:22Z"}