Hub documentation

Programmatic User Access Control Management

Hugging Face's logo
Join the Hugging Face community

and get access to the augmented documentation experience

to get started

Programmatic User Access Control Management

This guide describes how to manage organization member roles and resource group membership via the Hub API: changing a member’s organization role and resource group assignments, listing resource groups, adding users to groups, and batch workflows.

Table of contents:


Change member role via API

You can change a member’s organization role (Read / Contributor / Write / Admin) and, optionally, their roles in resource groups using the Hub API. The API updates one member per request. To change roles for multiple members, call the API in a loop (examples below).

OpenAPI reference: PUT /api/organizations/{name}/members/{username}/role

Prerequisites

  • Your organization must have a subscription plan (e.g. Team or Enterprise). The endpoint returns 402 otherwise.
  • You must be authenticated as an organization member with Write (or Admin) permission on the organization.
  • The target user must already be a member of the organization.

Base URL and authentication

  • Base URL: https://huggingface.co
  • Authentication: Send your token in the request header:
    Authorization: Bearer <your_access_token>
    Create a fine-grained token with the “Write access to organizations settings / member management” permission scoped to your org at https://huggingface.co/settings/tokens.

Change member role endpoint

Request

PUT /api/organizations/{org_name}/members/{username}/role
Authorization: Bearer <your_access_token>
Content-Type: application/json

{
  "role": "read",
  "resourceGroups": []
}
  • Path parameters
    • org_name: Organization slug (e.g. my-org).
    • username: Hugging Face username of the member whose role you are changing.
  • Body
    • role (required): The member’s organization-level role. One of: "read", "contributor", "write", or "admin".
    • resourceGroups (optional): Array of resource group assignments for this user. Each item:
      • id: Resource group ID (24-character hex string; get IDs from the resource groups list API).
      • role: Role in that resource group: "read", "contributor", "write", or "admin".
    • If you omit resourceGroups or pass [], the user is removed from all resource groups. To only change org role and leave resource groups unchanged, pass their current resource group memberships (the body always sets both org role and resource group list).

Example (curl) – set org role to “read”, no resource groups (removes any the user was previously in)

curl -s -X PUT \
  -H "Authorization: Bearer $HF_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"role":"read","resourceGroups":[]}' \
  "https://huggingface.co/api/organizations/my-org/members/member1/role"

Example (curl) – set org role and resource group roles (overrides any current groups)

curl -s -X PUT \
  -H "Authorization: Bearer $HF_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"role":"write","resourceGroups":[{"id":"507f1f77bcf86cd799439011","role":"read"}]}' \
  "https://huggingface.co/api/organizations/my-org/members/member2/role"

Success response: Status 200 OK; body: { "success": true }.

Typical errors

  • 400 — Invalid body (e.g. invalid role or resource group id).
  • 402 — Organization does not have a subscription plan.
  • 403 — Not allowed (e.g. you lack Write on the org, or a resource group is not in the org).
  • 404 — Organization or user not found.

Updating multiple members

The API changes one member per request. There is no bulk endpoint. To update many members, call the endpoint once per username (e.g. from a list or CSV).

Example: Bash – loop over usernames, same role for all

ORG_NAME="my-org"
ROLE="read"
for username in member1 member2 member3 member4; do
  echo "Setting $username to $ROLE ..."
  curl -s -w "\n%{http_code}" -X PUT \
    -H "Authorization: Bearer $HF_TOKEN" \
    -H "Content-Type: application/json" \
    -d "{\"role\":\"$ROLE\",\"resourceGroups\":[]}" \
    "https://huggingface.co/api/organizations/$ORG_NAME/members/$username/role"
  echo ""
done

Example: Python – loop over usernames

import os
import requests

BASE_URL = "https://huggingface.co"
HF_TOKEN = os.environ.get("HF_TOKEN", "")

def change_member_role(org_name: str, username: str, role: str, resource_groups: list | None = None):
    payload = {"role": role, "resourceGroups": resource_groups or []}
    r = requests.put(
        f"{BASE_URL}/api/organizations/{org_name}/members/{username}/role",
        headers={"Authorization": f"Bearer {HF_TOKEN}", "Content-Type": "application/json"},
        json=payload,
    )
    if r.status_code != 200:
        raise RuntimeError(f"{r.status_code}: {r.text}")
    return r.json()

org_name = "my-org"
role = "read"
for username in ["member1", "member2", "member3", "member4"]:
    print(f"Setting {username} to {role} ... ", end="")
    try:
        change_member_role(org_name, username, role)
        print("OK")
    except Exception as e:
        print(f"Failed: {e}")

For different roles per user, loop over (username, role) pairs (e.g. from a CSV) and call change_member_role for each.


Resource Groups API

The following endpoints let you list resource groups and add users to them. To change an existing member’s organization-level role or their resource group assignments, see Change member role via API above.

OpenAPI reference: Resource groups

Table of contents — API approaches:

Goal Section
Add many users to one resource group Add users to a resource group
Add the same users to many resource groups Batch-add by looping over the API
Add different users per group Batch-add by looping over the API

Base URL and authentication

  • Base URL: https://huggingface.co
  • Authentication: Use one of:
    • Access token (recommended for scripts): Create a fine-grained token with the “Write access to organizations settings / member management” permission scoped to your org at https://huggingface.co/settings/tokens. Send it in the request header:
      Authorization: Bearer <your_access_token>
    • Session cookie: If calling from a browser or tool that shares the same session as the Hub UI, the cookie is sent automatically.

List resource groups

Get all resource groups you can manage for the organization. Use this to obtain each group’s id for the add-users calls.

Request

GET /api/organizations/{org_name}/resource-groups
Authorization: Bearer <your_access_token>

Example (curl)

curl -s -H "Authorization: Bearer $HF_TOKEN" \
  "https://huggingface.co/api/organizations/my-org/resource-groups"

Example response (trimmed)

[
  {
    "id": "507f1f77bcf86cd799439011",
    "name": "Cohort 2024",
    "description": "Members in this group",
    "users": [...],
    "repos": [...]
  }
]

Use the id of each resource group when adding users.

Add users to a resource group

Add one or more users to a single resource group in one request. You can send multiple users in the same request.

Request

POST /api/organizations/{org_name}/resource-groups/{resource_group_id}/users
Authorization: Bearer <your_access_token>
Content-Type: application/json

{
  "users": [
    { "user": "member1", "role": "read" },
    { "user": "member2", "role": "read" },
    { "user": "member3", "role": "write" }
  ]
}
  • Path parameters
    • org_name: Organization slug (e.g. my-org).
    • resource_group_id: The resource group’s id (24-character hex string from the list endpoint).
  • Body
    • users: Array of objects. Each object must have:
      • user: Hugging Face username (required).
      • role: One of "read", "contributor", "write", "admin".

Example (curl)

curl -s -X POST \
  -H "Authorization: Bearer $HF_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"users":[{"user":"member1","role":"read"},{"user":"member2","role":"read"}]}' \
  "https://huggingface.co/api/organizations/my-org/resource-groups/507f1f77bcf86cd799439011/users"

Success: Status 200 OK; body is the updated resource group object (includes the new users in users).

Typical errors:

  • 400 — e.g. user not found, duplicate usernames, or invalid body.
  • 403 — Not allowed (e.g. not in org, or already in the resource group). The message will indicate whether users are not in the organization or already in the group.

Adding members via email (workaround)

The add-users endpoint only accepts Hugging Face usernames, not emails. If you have a list of emails (e.g. member emails), you can resolve email → username first, then call the add-users API.

Note that email filtering only works when the email’s domain matches one of the organization’s allowed domains: the Organization email domain (Settings → Account → Organization email domain) and/or the org’s SSO allowed domains (if SSO is configured).

Step 1 – Resolve email to username

GET /api/organizations/{org_name}/members?email={email}&limit=1
Authorization: Bearer <your_access_token>

Response is an array of members; each member has user (username). Use user for the add-users call.

Step 2 – Add to resource group

Use the username from step 1 in a normal add-users request:

POST /api/organizations/{org_name}/resource-groups/{resource_group_id}/users
Content-Type: application/json
Body: { "users": [{ "user": "<username from step 1>", "role": "read" }] }

Example: one email (bash)

ORG_NAME="my-org"
RG_ID="507f1f77bcf86cd799439011"
EMAIL="member@org.com"

# Step 1: look up member by email (domain must match org's Organization email domain or SSO allowed domains)
MEMBERS=$(curl -s -H "Authorization: Bearer $HF_TOKEN" \
  "https://huggingface.co/api/organizations/$ORG_NAME/members?email=$EMAIL&limit=1")
USERNAME=$(echo "$MEMBERS" | jq -r '(.[0] // {} | .user // "")')
if [ -z "$USERNAME" ]; then
  echo "No member found for $EMAIL"
  exit 1
fi
# Step 2: add to resource group
curl -s -X POST -H "Authorization: Bearer $HF_TOKEN" -H "Content-Type: application/json" \
  -d "{\"users\":[{\"user\":\"$USERNAME\",\"role\":\"read\"}]}" \
  "https://huggingface.co/api/organizations/$ORG_NAME/resource-groups/$RG_ID/users"

Example: multiple emails in a loop (Python)

import os
import requests

BASE = "https://huggingface.co"
ORG = "my-org"
RG_ID = "507f1f77bcf86cd799439011"
ROLE = "read"
headers = {"Authorization": f"Bearer {os.environ['HF_TOKEN']}", "Content-Type": "application/json"}

emails = ["member1@org.com", "member2@org.com"]
for email in emails:
    # Step 1: resolve email → username (email domain must match org's Organization email domain or SSO allowed domains)
    r = requests.get(f"{BASE}/api/organizations/{ORG}/members", params={"email": email, "limit": 1}, headers=headers)
    r.raise_for_status()
    members = r.json()
    if not members:
        print(f"No member found for {email}")
        continue
    username = members[0]["user"]
    # Step 2: add that user to the resource group
    add_r = requests.post(
        f"{BASE}/api/organizations/{ORG}/resource-groups/{RG_ID}/users",
        headers=headers,
        json={"users": [{"user": username, "role": ROLE}]},
    )
    if add_r.status_code == 200:
        print(f"Added {username} ({email})")
    else:
        print(f"Failed {email}: {add_r.status_code} {add_r.text}")

If a user is already in the resource group, the add call returns 403; the script reports it as a failure and you can skip or ignore that case if you prefer.

Limitation: The email filter only applies when the org has an Organization email domain and/or SSO allowed domains set, and the email’s domain matches one of them. Otherwise you cannot look up by email via the members API; you’d need another source for email → username (e.g. your own directory).

Batch-add by looping over the API

You can add many users to one resource group in one or a few requests (e.g. chunk your list of usernames), or add users to several resource groups by looping over groups and calling the add-users endpoint for each.

Example: Bash – one group, multiple users in one request

#!/bin/bash
# Add a list of users to a single resource group.
# Usage: ./add-users-to-rg.sh <org_name> <resource_group_id> <role>

ORG_NAME="${1:-my-org}"
RG_ID="${2:-507f1f77bcf86cd799439011}"
ROLE="${3:-read}"

USERS="member1 member2 member3 member4"
USERS_JSON=$(echo "$USERS" | tr ' ' '\n' | while read u; do
  [ -n "$u" ] && echo "{\"user\":\"$u\",\"role\":\"$ROLE\"}"
done | paste -sd ',' -)

curl -s -w "\nHTTP_STATUS:%{http_code}" -X POST \
  -H "Authorization: Bearer $HF_TOKEN" \
  -H "Content-Type: application/json" \
  -d "{\"users\":[$USERS_JSON]}" \
  "https://huggingface.co/api/organizations/$ORG_NAME/resource-groups/$RG_ID/users"

Example: Bash – loop over multiple groups

# Get group IDs and add users to each
curl -s -H "Authorization: Bearer $HF_TOKEN" \
  "https://huggingface.co/api/organizations/my-org/resource-groups" \
  | jq -r '.[].id' \
  | while read -r RG_ID; do
      [ -z "$RG_ID" ] && continue
      echo "Adding users to resource group $RG_ID ..."
      curl -s -X POST -H "Authorization: Bearer $HF_TOKEN" -H "Content-Type: application/json" \
        -d "{\"users\":[$USERS_JSON]}" \
        "https://huggingface.co/api/organizations/my-org/resource-groups/$RG_ID/users"
    done

Example: Python – batch-add to one or many groups

import os
import requests

BASE_URL = "https://huggingface.co"
HF_TOKEN = os.environ.get("HF_TOKEN", "")

def list_resource_groups(org_name: str):
    r = requests.get(
        f"{BASE_URL}/api/organizations/{org_name}/resource-groups",
        headers={"Authorization": f"Bearer {HF_TOKEN}"},
    )
    r.raise_for_status()
    return r.json()

def add_users_to_resource_group(org_name: str, resource_group_id: str, users_with_roles: list):
    """users_with_roles: list of {"user": "username", "role": "read"|"write"|"contributor"|"admin"}"""
    r = requests.post(
        f"{BASE_URL}/api/organizations/{org_name}/resource-groups/{resource_group_id}/users",
        headers={"Authorization": f"Bearer {HF_TOKEN}", "Content-Type": "application/json"},
        json={"users": users_with_roles},
    )
    if r.status_code != 200:
        raise RuntimeError(f"Add users failed {r.status_code}: {r.text}")
    return r.json()

# Example: same users added to every resource group
org_name = "my-org"
role = "read"
usernames = ["member1", "member2", "member3"]
users_with_roles = [{"user": u, "role": role} for u in usernames]

for rg in list_resource_groups(org_name):
    add_users_to_resource_group(org_name, rg["id"], users_with_roles)

For a long list of usernames, chunk them (e.g. 50 per request) and call the API once per chunk to avoid large request bodies or timeouts.

Important notes

  1. Usernames only — The API accepts Hugging Face usernames, not emails. You need a mapping from email → username (e.g. from your directory or the org members list) before calling the API.
  2. Users must be in the organization — Every user in the request must already be a member of the organization. Otherwise the request returns 403 with a message that some users are not in the org.
  3. Idempotency — If a user is already in the resource group, the backend may return 403 for that request. Your script can catch errors and continue, or skip users already in the group if you first fetch the group’s users list.
  4. Rate limits — For large batches, consider adding a short delay between requests (e.g. 0.5–1 second) to avoid hitting rate limits.
  5. Token scope — The access token must have sufficient permissions for the organization (typically at least “Write access to organizations settings / member management”). Create and store the token securely; do not commit it to version control.
Update on GitHub