Fetch Member Standing
curl --request GET \
--url https://api.sublay.io/v7/:projectId/workspaces/:id/members/:userId \
--header 'Authorization: Bearer <token>'import requests
url = "https://api.sublay.io/v7/:projectId/workspaces/:id/members/:userId"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api.sublay.io/v7/:projectId/workspaces/:id/members/:userId', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.sublay.io/v7/:projectId/workspaces/:id/members/:userId",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.sublay.io/v7/:projectId/workspaces/:id/members/:userId"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.sublay.io/v7/:projectId/workspaces/:id/members/:userId")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.sublay.io/v7/:projectId/workspaces/:id/members/:userId")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_bodyWorkspace — Membership
Fetch Member Standing
A user’s full resolved standing on a workspace, addressed by userId
Fetch Member Standing
curl --request GET \
--url https://api.sublay.io/v7/:projectId/workspaces/:id/members/:userId \
--header 'Authorization: Bearer <token>'import requests
url = "https://api.sublay.io/v7/:projectId/workspaces/:id/members/:userId"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api.sublay.io/v7/:projectId/workspaces/:id/members/:userId', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.sublay.io/v7/:projectId/workspaces/:id/members/:userId",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.sublay.io/v7/:projectId/workspaces/:id/members/:userId"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.sublay.io/v7/:projectId/workspaces/:id/members/:userId")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.sublay.io/v7/:projectId/workspaces/:id/members/:userId")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_bodyReturns a single user’s full standing on a workspace, addressed by
Caller with a plain relation, reading someone else’s standing — the four authority fields are simply absent:
Every path id on the workspaces bundle is checked for UUID shape before the route runs, so a malformed one is a plain
See also: useFetchWorkspaceMemberStanding · List Members · Read Authority
userId (not a membership-row id, so it works for users with no direct row). Returns the same unified shape as one roster row, computed on demand for any relation — direct member, this workspace’s owner, an ancestor-owner, or a reach-holder. Returns empty/none only if the user has no relation at all.
Requires roster visibility — any relation to the workspace (owner, ancestor-owner, member, or reach-holder).
reasons is an array of structured entries — { type, viaWorkspaceId? } — the same object shape a roster entry’s reasons carries. viaWorkspaceId names the granting ancestor and appears on ancestor-owner / reach-holder only.
The authority-bearing fields are fenced, and the gate is scoped to THIS workspace.
capabilities, permissions, rank and relativeRank are omitted from the response (absent — not null) unless the caller:- holds one of the four people-operating capabilities on this workspace —
invite,remove-member,edit-member-access,edit-member-profile; or - is this workspace’s
owneror anancestor-owner; or - is asking about themselves (a caller always sees their own access); or
- is a service/master key acting as itself (naming no
actingUserId). A key that does name one is fenced exactly as that user is — see Acting on behalf of a user.
descendant-member row it returns, so the two reads agree node for node.Everything else — user, reasons, title, metadata — is visible to any relation. Treat these four fields as optional in your types.relativeRank is fenced with rank, not beside it: it is rank minus the caller’s own anchor, a number the caller already knows, so returning it to a fenced caller would reconstruct the fenced rank exactly.Path Parameters
string
required
The workspace UUID.
string
required
The target user whose standing to read.
Query Parameters
string
Service/master keys only — the user to act as. Enforced: roster visibility and the authority-field fence above both evaluate against the named user, so a key acting as a plain member receives the fenced standing (and the full one when asking about that user themselves). Omit it to read as the app itself (unfenced). See Acting on behalf of a user.
Response
Caller who may see authority fields (a people-operator, an owner, or the user themselves):{
"user": { "id": "u_pat" },
"reasons": [
{ "type": "member" },
{ "type": "ancestor-owner", "viaWorkspaceId": "ws_root" }
],
"capabilities": ["view", "invite", "remove-member"],
"permissions": ["deploy"],
"rank": 5,
"relativeRank": 2,
"title": "Frontend Lead",
"metadata": {}
}
{
"user": { "id": "u_pat" },
"reasons": [
{ "type": "member" },
{ "type": "ancestor-owner", "viaWorkspaceId": "ws_root" }
],
"title": "Frontend Lead",
"metadata": {}
}
reasonsis always present;viaWorkspaceIdappears onancestor-owner/reach-holderentries only.capabilitiesis the resolved set (direct + reach + ownership).viewis implied by every other capability — anyone with standing resolves withview, including a member whose storedcapabilitiesarray is empty. A user with no relation at all returnsreasons: []and an empty capability set.permissionsis per-node (the direct membership on this workspace only; may be empty).rankis the direct-membership rank, ornullfor owners / ancestor-owners / reach-only holders (they sit outside the numbered ladder).relativeRankis that same position expressed as an offset from the caller —2above means the target sits two rungs below you; a negative value means they are senior to you, and0means they are your peer.nullexactly whenrankisnull. The caller’s own anchor is their member row on this workspace if they hold one, and apex (one step above rank 0) otherwise — so an owner reads a rank-0 member back as1. See rank semantics.
Error Responses
Invalid Path Parameter — 400
Invalid Path Parameter — 400
{ "error": "Invalid workspace id: expected a UUID.", "code": "workspace/invalid-params" }
400 rather than a 500 from the database.
