Organizations

Update Member Site Access

Restricts a member to specific sites, optionally raising their role on those sites, or lifts the restriction.

PUT /api/organizations/:organizationId/members/:memberId/sites

Sets which sites a member can reach and the role they hold on them. This replaces the member's site grants: the siteIds you send become the full list.

  • With hasRestrictedSiteAccess: true, the member reaches siteIds plus any sites granted to teams they belong to.
  • With hasRestrictedSiteAccess: false, their per-site grants are removed and they reach every site that isn't limited to a team, plus the sites of their own teams. Sites limited to teams they aren't on stay hidden.

Team grants are managed separately, with Teams.

siteRole raises the member's role on the granted sites above their organization role (for example, an organization viewer who is an editor on one site). It never lowers it, and it stops at editor. Admins and owners always reach every site and can't be restricted.

Permissions: the admin role or above in the organization. API keys need the org:write scope.

Path Parameters

Prop

Type

Request Body

Prop

Type

Response

Prop

Type

Error Responses

Errors use the standard body { error, code, message, resolution }.

Prop

Type

Request
curl -X PUT "https://app.rybbit.io/api/organizations/org_123/members/mem_7c6d5e4f3g2h/sites" \
  -H "Authorization: Bearer your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "hasRestrictedSiteAccess": true,
    "siteIds": [
      123,
      456
    ],
    "siteRole": "editor"
  }'
Request
const response = await fetch(
  'https://app.rybbit.io/api/organizations/org_123/members/mem_7c6d5e4f3g2h/sites',
  {
    method: 'PUT',
    headers: {
      'Authorization': 'Bearer your_api_key_here',
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      hasRestrictedSiteAccess: true,
      siteIds: [123, 456],
      siteRole: 'editor'
    })
  }
);

const data = await response.json();
Request
import requests

response = requests.put(
    'https://app.rybbit.io/api/organizations/org_123/members/mem_7c6d5e4f3g2h/sites',
    json={
        'hasRestrictedSiteAccess': True,
        'siteIds': [123, 456],
        'siteRole': 'editor'
    },
    headers={
        'Authorization': 'Bearer your_api_key_here'
    }
)

data = response.json()
Request
$body = [
    'hasRestrictedSiteAccess' => true,
    'siteIds' => [123, 456],
    'siteRole' => 'editor'
];

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://app.rybbit.io/api/organizations/org_123/members/mem_7c6d5e4f3g2h/sites');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT');
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($body));
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'Authorization: Bearer your_api_key_here',
    'Content-Type: application/json'
]);

$response = curl_exec($ch);
curl_close($ch);

$data = json_decode($response, true);
Request
require 'net/http'
require 'json'

uri = URI('https://app.rybbit.io/api/organizations/org_123/members/mem_7c6d5e4f3g2h/sites')
request = Net::HTTP::Put.new(uri)
request['Authorization'] = 'Bearer your_api_key_here'
request['Content-Type'] = 'application/json'
request.body = {
  hasRestrictedSiteAccess: true,
  siteIds: [123, 456],
  siteRole: 'editor'
}.to_json

response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
  http.request(request)
end

data = JSON.parse(response.body)
Request
body := map[string]interface{}{
    "hasRestrictedSiteAccess": true,
    "siteIds": []interface{}{123, 456},
    "siteRole": "editor",
}
jsonBody, _ := json.Marshal(body)

req, _ := http.NewRequest("PUT", "https://app.rybbit.io/api/organizations/org_123/members/mem_7c6d5e4f3g2h/sites", bytes.NewBuffer(jsonBody))
req.Header.Set("Authorization", "Bearer your_api_key_here")
req.Header.Set("Content-Type", "application/json")

client := &http.Client{}
resp, _ := client.Do(req)
defer resp.Body.Close()

var data map[string]interface{}
json.NewDecoder(resp.Body).Decode(&data)
Request
let body = serde_json::json!({
  "hasRestrictedSiteAccess": true,
  "siteIds": [
    123,
    456
  ],
  "siteRole": "editor"
});

let client = reqwest::Client::new();
let res = client
    .put("https://app.rybbit.io/api/organizations/org_123/members/mem_7c6d5e4f3g2h/sites")
    .header("Authorization", "Bearer your_api_key_here")
    .json(&body)
    .send()
    .await?;

let data: serde_json::Value = res.json().await?;
Request
String json = """
{
  "hasRestrictedSiteAccess": true,
  "siteIds": [
    123,
    456
  ],
  "siteRole": "editor"
}
""";

HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://app.rybbit.io/api/organizations/org_123/members/mem_7c6d5e4f3g2h/sites"))
    .header("Authorization", "Bearer your_api_key_here")
    .header("Content-Type", "application/json")
    .PUT(HttpRequest.BodyPublishers.ofString(json))
    .build();

HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
Request
var body = new
{
    hasRestrictedSiteAccess = true,
    siteIds = new[] { 123, 456 },
    siteRole = "editor"
};

using var client = new HttpClient();
client.DefaultRequestHeaders.Add("Authorization", "Bearer your_api_key_here");

var content = new StringContent(
    JsonSerializer.Serialize(body),
    Encoding.UTF8,
    "application/json");

var response = await client.PutAsync("https://app.rybbit.io/api/organizations/org_123/members/mem_7c6d5e4f3g2h/sites", content);
var data = await response.Content.ReadAsStringAsync();
Response
{
  "memberId": "mem_7c6d5e4f3g2h",
  "hasRestrictedSiteAccess": true,
  "siteAccess": [
    {
      "siteId": 123,
      "role": "editor",
      "name": "Acme",
      "domain": "acme.com"
    },
    {
      "siteId": 456,
      "role": "editor",
      "name": "Acme Docs",
      "domain": "docs.acme.com"
    }
  ]
}