desk-ops

Embed
Preview of the card
<a href="https://forumulate.com/p/gaiadesk/docs/ref-desk-ops"><img src="https://forumulate.com/api/public/orgs/gaiadesk/spaces/docs/pages/296a123f-0d4f-4dec-8a90-f657e63dae10/social-card.svg?v=3e7ae33eec8b" alt="desk-ops" width="600" height="315"></a>
GEThttps://api.gaiadesk.net/v1/desks/{id}/tokensScope tokens

The desk's agent tokens (never their secrets).

Token administration is the desk OWNER's: a signed-in person's own account on their own desk. An agent token is refused whatever its scopes (403 agent_cannot_admin).

Parameters

idstringpathrequired
The desk's nine-digit id.
GaiaDesk-E2Estringheader
End-to-end encrypted: the sealed request (ApiE2eRequest, as base64url of its JSON) in place of a plaintext body or parameters. The answer is then sealed too (ApiE2eAnswer, ApiE2eStreamEvent, ApiE2eFrame). A POST may instead send the body {"e2e": …} (ApiE2eBody). See the "End-to-end encryption" section of docs/api/README.md.
wake_sintegerquery
If the desk is asleep, ring it and wait up to this long (default 60, at most 120).

Code samples

cURL
curl -X GET "https://api.gaiadesk.net/v1/desks/{id}/tokens" \
  -H "Authorization: Bearer $GAIADESK_API_KEY" \
  -H "GaiaDesk-E2E: <value>"
TypeScript
Python
Go
PHP
Ruby
Java

Responses

200 The tokens.
Example
{
  "tokens": [
    {
      "cwd": "string",
      "expires_at_ms": 0,
      "id": "string",
      "issued_at_ms": 0,
      "label": "string",
      "last_used_ms": 0,
      "low_priv": true,
      "revoked": false,
      "scopes": []
    }
  ]
}
TokenList
tokensTokenInfo[]required
Show child parameters
cwdstring
The directory this token's work is confined to: its commands, shells and jobs start there, and every path it copies must resolve inside it (links resolved first). None: not confined.
expires_at_msintegerrequired
idstringrequired
The token's non-secret id (a digest of its stored hash).
issued_at_msintegerrequired
labelstringrequired
last_used_msinteger
low_privboolean
Its commands, shells and jobs run as the desk's low-privilege agent user (set on the desk), or are refused — never as the desk's own user.
revokedboolean
= false
scopesstring[]
What it may do: screen, exec, shell, cp, forward, jobs, admin (ask to run as administrator — never implied). Empty for a token from before scopes, which is a screen (Agent Access) token.
= []
{
  "tokens": [
    {
      "cwd": "string",
      "expires_at_ms": 0,
      "id": "string",
      "issued_at_ms": 0,
      "label": "string",
      "last_used_ms": 0,
      "low_priv": true,
      "revoked": false,
      "scopes": []
    }
  ]
}
ApiE2eAnswer
e2eobjectrequired
Show child parameters
vintegerrequired
eventsApiE2eFrame[]required
Show child parameters
seqintegerrequired
noncestringrequired
ciphertextstringrequired
{
  "e2e": {
    "v": 0,
    "events": [
      {
        "seq": 0,
        "nonce": "string",
        "ciphertext": "string"
      }
    ]
  }
}
Headers
X-Request-Idstring
This request's id (req_…), also in every error body. Quote it to support.
RateLimit-Limitinteger
Requests allowed per window for this key.
RateLimit-Remaininginteger
Requests left in the current window.
RateLimit-Resetinteger
Seconds until the window resets.
400 The request is malformed (usage).
Example
{
  "error": {
    "desk": "string",
    "kind": "string",
    "message": "string",
    "reason": "string",
    "request_id": "string",
    "status": 0
  },
  "e2e": {
    "v": 0,
    "events": [
      {
        "seq": 0,
        "nonce": "string",
        "ciphertext": "string"
      }
    ]
  }
}
Schema
errorError & objectrequired
The CLI's error object plus this request's id.
Show child parameters
deskstring
The desk it concerned, when there was one.
kindstringrequired
The six kinds a program branches on. Stable: a new kind would be a breaking change, so match with a wildcard arm anyway.
messagestringrequired
reasonstring
The finer cause: offline, unknown_desk, not_online, network, not_signed_in, timeout, local, …
request_idstringrequired
statusinteger
Only in a held body (GaiaDesk-Held) — the HTTP status this failure would have had, had its 200 not been sent already.
e2eobject
An end-to-end encrypted operation's events; the last opens to the desk's real error (its message here is a placeholder).
Show child parameters
vintegerrequired
eventsApiE2eFrame[]required
Show child parameters
seqintegerrequired
noncestringrequired
ciphertextstringrequired
401 No credential, or one that does not verify (refused, unauthenticated).

Same as 400 · GET /desks/{id}/tokens

403 The credential lacks the scope, or may not use this API (refused).

Same as 400 · GET /desks/{id}/tokens

404 No such desk or resource visible to the caller (unreachable, unknown_desk).

Same as 400 · GET /desks/{id}/tokens

409 The desk is offline (unreachable, with the reach log's reason: silent, closed, …) or could not be woken within wake_s; or it runs a GaiaDesk from before desk operations (protocol, desk_too_old: update GaiaDesk on this desk).

Same as 400 · GET /desks/{id}/tokens

429 Over this key's rate limit (rate_limited), or the desk already runs 16 API operations (desk_busy).

Same as 400 · GET /desks/{id}/tokens

Headers
Retry-Afterinteger
Seconds to wait before trying again.
502 The desk went away during the operation (connection_lost), or answered something this server cannot read (protocol).

Same as 400 · GET /desks/{id}/tokens

503 Desk operations are turned off on this server (unreachable, desk_ops_disabled).

Same as 400 · GET /desks/{id}/tokens

default The error envelope.

Same as 400 · GET /desks/{id}/tokens

POSThttps://api.gaiadesk.net/v1/desks/{id}/tokensScope tokens

Mint a scoped agent token on the desk (the secret is returned once).

Token administration is the desk OWNER's: a signed-in person's own account on their own desk. An agent token is refused whatever its scopes (403 agent_cannot_admin).

The admin scope cannot be minted through the API (403 refused, error.reason admin_not_via_api): its secret would cross the API. Mint it with gaiadesk-cli token create --scope exec,admin (docs/admin-access.md).

Parameters

idstringpathrequired
The desk's nine-digit id.
GaiaDesk-E2Estringheader
End-to-end encrypted: the sealed request (ApiE2eRequest, as base64url of its JSON) in place of a plaintext body or parameters. The answer is then sealed too (ApiE2eAnswer, ApiE2eStreamEvent, ApiE2eFrame). A POST may instead send the body {"e2e": …} (ApiE2eBody). See the "End-to-end encryption" section of docs/api/README.md.
Idempotency-Keystringheader
Up to 255 printable ASCII characters. A retry with the same key and the same request within 24 hours gets the first answer again (Idempotent-Replayed: true); the same key with a different request is refused (usage, idempotency_key_reused).
wake_sintegerquery
If the desk is asleep, ring it and wait up to this long (default 60, at most 120).

Request body

application/json
Example
{
  "cwd": "string",
  "expires_secs": 0,
  "low_priv": false,
  "name": "string",
  "scopes": {}
}
ApiMintSpec
cwdstring
The directory on the desk the token's work is confined to.
expires_secsintegerrequired
low_privboolean
Its work runs as the desk's low-privilege agent user.
= false
namestringrequired
scopesrequired
{
  "cwd": "string",
  "expires_secs": 0,
  "low_priv": false,
  "name": "string",
  "scopes": {}
}
ApiE2eBody
e2eobjectrequired
A desk operation sealed to the desk's key (e2e_pub): X25519 with the caller's ephemeral key pub, HKDF-SHA256, XChaCha20-Poly1305 (protocol/src/e2e.rs; docs/api/README.md). Base64url, no padding.
Show child parameters
vinteger
pubstringrequired
The caller's ephemeral X25519 public key (32 bytes).
noncestringrequired
24 bytes.
ciphertextstringrequired
{
  "e2e": {
    "v": 0,
    "pub": "string",
    "nonce": "string",
    "ciphertext": "string"
  }
}

Code samples

cURL
curl -X POST "https://api.gaiadesk.net/v1/desks/{id}/tokens" \
  -H "Authorization: Bearer $GAIADESK_API_KEY" \
  -H "GaiaDesk-E2E: <value>" \
  -H "Idempotency-Key: <value>" \
  -H "Content-Type: application/json" \
  -d '{"cwd":"string","expires_secs":0,"low_priv":false,"name":"string","scopes":{}}'
TypeScript
Python
Go
PHP
Ruby
Java

Responses

201 Minted.
Example
{
  "tokens": [
    {
      "desk": "string",
      "secret": "string",
      "token": {
        "cwd": "string",
        "expires_at_ms": 0,
        "id": "string",
        "issued_at_ms": 0,
        "label": "string",
        "last_used_ms": 0,
        "low_priv": true,
        "revoked": false,
        "scopes": []
      }
    }
  ]
}
MintResult
tokensMintedToken[]required
Show child parameters
deskstringrequired
secretstringrequired
tokenobjectrequired
One agent token as its desk's owner sees it: everything but the secret.
Show child parameters
cwdstring
The directory this token's work is confined to: its commands, shells and jobs start there, and every path it copies must resolve inside it (links resolved first). None: not confined.
expires_at_msintegerrequired
idstringrequired
The token's non-secret id (a digest of its stored hash).
issued_at_msintegerrequired
labelstringrequired
last_used_msinteger
low_privboolean
Its commands, shells and jobs run as the desk's low-privilege agent user (set on the desk), or are refused — never as the desk's own user.
revokedboolean
= false
scopesstring[]
What it may do: screen, exec, shell, cp, forward, jobs, admin (ask to run as administrator — never implied). Empty for a token from before scopes, which is a screen (Agent Access) token.
= []
{
  "tokens": [
    {
      "desk": "string",
      "secret": "string",
      "token": {
        "cwd": "string",
        "expires_at_ms": 0,
        "id": "string",
        "issued_at_ms": 0,
        "label": "string",
        "last_used_ms": 0,
        "low_priv": true,
        "revoked": false,
        "scopes": []
      }
    }
  ]
}
ApiE2eAnswer
e2eobjectrequired
Show child parameters
vintegerrequired
eventsApiE2eFrame[]required
Show child parameters
seqintegerrequired
noncestringrequired
ciphertextstringrequired
{
  "e2e": {
    "v": 0,
    "events": [
      {
        "seq": 0,
        "nonce": "string",
        "ciphertext": "string"
      }
    ]
  }
}
Headers
X-Request-Idstring
This request's id (req_…), also in every error body. Quote it to support.
RateLimit-Limitinteger
Requests allowed per window for this key.
RateLimit-Remaininginteger
Requests left in the current window.
RateLimit-Resetinteger
Seconds until the window resets.
Idempotent-Replayedstring
true when this answer is a stored one, replayed for a repeated Idempotency-Key.
400 The request is malformed (usage).

Same as 400 · GET /desks/{id}/tokens

401 No credential, or one that does not verify (refused, unauthenticated).

Same as 400 · GET /desks/{id}/tokens

403 The credential lacks the scope, or may not use this API (refused).

Same as 400 · GET /desks/{id}/tokens

404 No such desk or resource visible to the caller (unreachable, unknown_desk).

Same as 400 · GET /desks/{id}/tokens

409 The desk is offline (unreachable, with the reach log's reason: silent, closed, …) or could not be woken within wake_s; or it runs a GaiaDesk from before desk operations (protocol, desk_too_old: update GaiaDesk on this desk).

Same as 400 · GET /desks/{id}/tokens

429 Over this key's rate limit (rate_limited), or the desk already runs 16 API operations (desk_busy).

Same as 400 · GET /desks/{id}/tokens

Headers
Retry-Afterinteger
Seconds to wait before trying again.
502 The desk went away during the operation (connection_lost), or answered something this server cannot read (protocol).

Same as 400 · GET /desks/{id}/tokens

503 Desk operations are turned off on this server (unreachable, desk_ops_disabled).

Same as 400 · GET /desks/{id}/tokens

default The error envelope.

Same as 400 · GET /desks/{id}/tokens

DELETEhttps://api.gaiadesk.net/v1/desks/{id}/tokens/{token_id}Scope tokens

Revoke an agent token; its live sessions and jobs end.

Token administration is the desk OWNER's: a signed-in person's own account on their own desk. An agent token is refused whatever its scopes (403 agent_cannot_admin).

Parameters

idstringpathrequired
The desk's nine-digit id.
token_idstringpathrequired
The token's id or name.
GaiaDesk-E2Estringheader
End-to-end encrypted: the sealed request (ApiE2eRequest, as base64url of its JSON) in place of a plaintext body or parameters. The answer is then sealed too (ApiE2eAnswer, ApiE2eStreamEvent, ApiE2eFrame). A POST may instead send the body {"e2e": …} (ApiE2eBody). See the "End-to-end encryption" section of docs/api/README.md.
wake_sintegerquery
If the desk is asleep, ring it and wait up to this long (default 60, at most 120).

Code samples

cURL
curl -X DELETE "https://api.gaiadesk.net/v1/desks/{id}/tokens/{token_id}" \
  -H "Authorization: Bearer $GAIADESK_API_KEY" \
  -H "GaiaDesk-E2E: <value>"
TypeScript
Python
Go
PHP
Ruby
Java

Responses

200 Revoked.
Example
{
  "revoked": "string",
  "stopped_sessions": 0
}
Revoked
revokedstringrequired
stopped_sessionsintegerrequired
{
  "revoked": "string",
  "stopped_sessions": 0
}
ApiE2eAnswer
e2eobjectrequired
Show child parameters
vintegerrequired
eventsApiE2eFrame[]required
Show child parameters
seqintegerrequired
noncestringrequired
ciphertextstringrequired
{
  "e2e": {
    "v": 0,
    "events": [
      {
        "seq": 0,
        "nonce": "string",
        "ciphertext": "string"
      }
    ]
  }
}
Headers
X-Request-Idstring
This request's id (req_…), also in every error body. Quote it to support.
RateLimit-Limitinteger
Requests allowed per window for this key.
RateLimit-Remaininginteger
Requests left in the current window.
RateLimit-Resetinteger
Seconds until the window resets.
400 The request is malformed (usage).

Same as 400 · GET /desks/{id}/tokens

401 No credential, or one that does not verify (refused, unauthenticated).

Same as 400 · GET /desks/{id}/tokens

403 The credential lacks the scope, or may not use this API (refused).

Same as 400 · GET /desks/{id}/tokens

404 No such desk or resource visible to the caller (unreachable, unknown_desk).

Same as 400 · GET /desks/{id}/tokens

409 The desk is offline (unreachable, with the reach log's reason: silent, closed, …) or could not be woken within wake_s; or it runs a GaiaDesk from before desk operations (protocol, desk_too_old: update GaiaDesk on this desk).

Same as 400 · GET /desks/{id}/tokens

429 Over this key's rate limit (rate_limited), or the desk already runs 16 API operations (desk_busy).

Same as 400 · GET /desks/{id}/tokens

Headers
Retry-Afterinteger
Seconds to wait before trying again.
502 The desk went away during the operation (connection_lost), or answered something this server cannot read (protocol).

Same as 400 · GET /desks/{id}/tokens

503 Desk operations are turned off on this server (unreachable, desk_ops_disabled).

Same as 400 · GET /desks/{id}/tokens

default The error envelope.

Same as 400 · GET /desks/{id}/tokens

Updated