Hub documentation
Programmatic User Access Control Management
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 — Set a member’s org role and resource group assignments (one member per request).
- Resource Groups API — List resource groups and add users to them.
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:
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.
Authorization: Bearer <your_access_token>
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
resourceGroupsor 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 groupid).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 ""
doneExample: 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.
- 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:
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’sid(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"
doneExample: 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
- 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.
- Users must be in the organization — Every user in the request must already be a member of the organization. Otherwise the request returns
403with a message that some users are not in the org. - Idempotency — If a user is already in the resource group, the backend may return
403for that request. Your script can catch errors and continue, or skip users already in the group if you first fetch the group’suserslist. - Rate limits — For large batches, consider adding a short delay between requests (e.g. 0.5–1 second) to avoid hitting rate limits.
- 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.