Sharing
Internal sharing: shares, members, and invitations. Everything that happens inside your tenant with people who have (or will have) accounts.
For sharing content with anonymous users via public URLs, see External Links.
Base path: /api/v1/shares/
Creating a share
| curl -X POST $SCAIDRIVE_URL/api/v1/shares \
-H "Authorization: Bearer $SCAIDRIVE_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Q2 Planning",
"share_type": "project",
"owner_id": "grp_01J3L"
}'
|
| resp = httpx.post(
f"{url}/api/v1/shares",
headers={"Authorization": f"Bearer {token}"},
json={"name": "Q2 Planning", "share_type": "project", "owner_id": "grp_01J3L"},
)
share = resp.json()
|
1
2
3
4
5
6
7
8
9
10
11
12
13 | const resp = await fetch(`${url}/api/v1/shares`, {
method: "POST",
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
name: "Q2 Planning",
share_type: "project",
owner_id: "grp_01J3L",
}),
});
const share = await resp.json();
|
Fields:
| Field |
Notes |
name (required) |
Display name |
share_type (required) |
central, personal, or project |
owner_id (required) |
usr_... or grp_... — who owns the share |
description |
Optional |
quota_bytes |
Optional; omit to inherit tenant quota |
See Shares and Ownership for the types.
Listing your shares
| curl -H "Authorization: Bearer $SCAIDRIVE_TOKEN" \
$SCAIDRIVE_URL/api/v1/users/me/shares
|
Returns shares you're a member of (directly or via a group), with your role in each.
To list all shares in the tenant (admin view):
| curl -H "Authorization: Bearer $SCAIDRIVE_TOKEN" \
$SCAIDRIVE_URL/api/v1/shares
|
Query parameters limit, offset, and include_trashed apply.
Searching for principals
Before adding a member, look up the user or group:
| curl -G $SCAIDRIVE_URL/api/v1/shares/search/principals \
-H "Authorization: Bearer $SCAIDRIVE_TOKEN" \
--data-urlencode "q=alice" \
--data-urlencode "principal_type=user"
|
| {
"users": [
{"id": "usr_01J4M", "email": "alice@example.com", "name": "Alice Cooper"}
],
"groups": []
}
|
Search hits email, name, and display_name. Omit principal_type to search both users and groups.
Adding a member
| curl -X POST $SCAIDRIVE_URL/api/v1/shares/shr_01J3K/members \
-H "Authorization: Bearer $SCAIDRIVE_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"principal_type": "user",
"principal_id": "usr_01J4M",
"role": "contributor"
}'
|
With time-bounded access:
| {
"principal_type": "user",
"principal_id": "usr_01J4M",
"role": "reader",
"expires_at": "2026-07-01T00:00:00Z"
}
|
Requires MANAGE_PERMISSIONS on the share — effectively owner or admin role.
Role options: owner, admin, contributor, reader. See Shares and Ownership.
Listing members
| curl -H "Authorization: Bearer $SCAIDRIVE_TOKEN" \
$SCAIDRIVE_URL/api/v1/shares/shr_01J3K/members
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 | {
"members": [
{
"principal_type": "group",
"principal_id": "grp_01J3L",
"principal_name": "Engineering",
"role": "admin",
"granted_by": "usr_01J3N",
"expires_at": null
},
{
"principal_type": "user",
"principal_id": "usr_01J4M",
"principal_name": "Alice Cooper",
"role": "contributor",
"granted_by": "usr_01J3N",
"expires_at": "2026-07-01T00:00:00Z"
}
],
"total": 2
}
|
Changing a member's role
| curl -X PATCH $SCAIDRIVE_URL/api/v1/shares/shr_01J3K/members/usr_01J4M \
-H "Authorization: Bearer $SCAIDRIVE_TOKEN" \
-H "Content-Type: application/json" \
-d '{"role": "admin"}'
|
You can also change expires_at.
Removing a member
| curl -X DELETE $SCAIDRIVE_URL/api/v1/shares/shr_01J3K/members/usr_01J4M \
-H "Authorization: Bearer $SCAIDRIVE_TOKEN"
|
Revoking group membership removes access for every user in that group (unless they have direct membership in addition).
Inviting someone who doesn't have an account
For users not yet provisioned in ScaiKey, send an invitation:
| curl -X POST $SCAIDRIVE_URL/api/v1/shares/shr_01J3K/invite \
-H "Authorization: Bearer $SCAIDRIVE_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"email": "partner@external.com",
"role": "reader",
"message": "Here are the specs we discussed.",
"expires_in_days": 14
}'
|
Response:
| {
"id": "inv_01J5N",
"email": "partner@external.com",
"role": "reader",
"status": "pending",
"token": "opaque-invitation-token",
"expires_at": "2026-05-07T10:15:00Z"
}
|
An email is sent via ScaiSend with a link containing the token. When the recipient clicks:
- They authenticate via ScaiKey (creating an account if new).
- ScaiDrive provisions the user JIT.
- They call
POST /api/v1/users/me/invitations/{invitation_id}/accept.
- A
ShareMember record is created with the invitation's role.
Pending invitations for the calling user:
| curl -H "Authorization: Bearer $SCAIDRIVE_TOKEN" \
$SCAIDRIVE_URL/api/v1/users/me/invitations
|
Accept or decline:
| curl -X POST $SCAIDRIVE_URL/api/v1/users/me/invitations/inv_01J5N/accept \
-H "Authorization: Bearer $SCAIDRIVE_TOKEN"
curl -X POST $SCAIDRIVE_URL/api/v1/users/me/invitations/inv_01J5N/decline \
-H "Authorization: Bearer $SCAIDRIVE_TOKEN"
|
Revoke a pending invitation:
| curl -X DELETE $SCAIDRIVE_URL/api/v1/shares/shr_01J3K/invitations/inv_01J5N \
-H "Authorization: Bearer $SCAIDRIVE_TOKEN"
|
Listing pending invitations on a share
| curl -H "Authorization: Bearer $SCAIDRIVE_TOKEN" \
$SCAIDRIVE_URL/api/v1/shares/shr_01J3K/invitations
|
Returns invitations with status pending. Filter by status if you want the history — ?status=all.
Per-file and per-folder access
Sometimes you want to grant one person access to one file within a share they're not a member of. For that, use the ACL API directly:
| curl -X POST $SCAIDRIVE_URL/api/v1/permissions/acl/file/fil_01J3M \
-H "Authorization: Bearer $SCAIDRIVE_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"principal_type": "user",
"principal_id": "usr_01J4M",
"permissions": ["READ"],
"ace_type": "allow",
"inherit_to_children": false
}'
|
This doesn't make them a share member — they can access the file, but not see or list the share. See Permissions and ACLs.
For external parties without any ScaiDrive account, use External Links.
Updating the share itself
| curl -X PATCH $SCAIDRIVE_URL/api/v1/shares/shr_01J3K \
-H "Authorization: Bearer $SCAIDRIVE_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name": "Q2 Planning (archived)"}'
|
Requires MANAGE_PERMISSIONS. You can change name and description.
Deleting a share
| curl -X DELETE $SCAIDRIVE_URL/api/v1/shares/shr_01J3K \
-H "Authorization: Bearer $SCAIDRIVE_TOKEN"
|
Soft-deletes the share. Content is preserved for the tenant's trash-retention window. Permanent deletion requires tenant admin.
Common recipes
Give a group read-only access
| httpx.post(
f"{url}/api/v1/shares/{share_id}/members",
headers={"Authorization": f"Bearer {token}"},
json={"principal_type": "group", "principal_id": group_id, "role": "reader"},
)
|
Time-bounded contractor access
1
2
3
4
5
6
7
8
9
10
11
12
13 | import datetime as dt
expires = (dt.datetime.now(dt.UTC) + dt.timedelta(days=90)).isoformat()
httpx.post(
f"{url}/api/v1/shares/{share_id}/members",
headers={"Authorization": f"Bearer {token}"},
json={
"principal_type": "user",
"principal_id": contractor_id,
"role": "contributor",
"expires_at": expires,
},
)
|
Invite several external users at once
| for email in ["a@ext.com", "b@ext.com", "c@ext.com"]:
httpx.post(
f"{url}/api/v1/shares/{share_id}/invite",
headers={"Authorization": f"Bearer {token}"},
json={"email": email, "role": "reader", "expires_in_days": 30},
)
|
What's next