Build
Organizations, teams and folder access
Put a studio's people, teams and spaces together, give teams roles in spaces, limit who may change a folder, sign in through your identity provider and export the audit trail.
An organization holds a company's people and its teams. A space can belong to one organization, and then its teams can have roles in it: someone who joins the editorial team gets the editorial team's access to every project at once, and loses it when they leave. Spaces outside organizations work exactly as before.
| Organization role | May |
|---|---|
owner | Everything an admin may, plus appoint owners and set up single sign-on. The last owner can't leave. |
admin | Add and remove people, make teams, bring spaces they manage into the organization, export the audit trail. |
member | See the organization's people, teams and the spaces they are in. |
People and teams
sidespace org create "Harbor Pictures"
sidespace org members "Harbor Pictures" --add [email protected] --role admin
sidespace team create "Harbor Pictures" Editorial
sidespace team add "Harbor Pictures" Editorial [email protected] [email protected]
sidespace org attach "Film A" "Harbor Pictures" # you manage Film A and are an admin there
sidespace team grant "Film A" Editorial editorcurl -X POST "https://side.example.com/v1/orgs" -H "Authorization: Bearer $SIDESPACE_TOKEN" \
-H "Content-Type: application/json" -d '{"name": "Harbor Pictures"}'
curl -X POST "https://side.example.com/v1/orgs/$ORG/teams" -H "Authorization: Bearer $SIDESPACE_TOKEN" \
-H "Content-Type: application/json" -d '{"name": "Editorial"}'
curl -X POST "https://side.example.com/v1/orgs/$ORG/teams/$TEAM/members" -H "Authorization: Bearer $SIDESPACE_TOKEN" \
-H "Content-Type: application/json" -d '{"email": "[email protected]"}'
curl -X PUT "https://side.example.com/v1/spaces/$SPACE/org" -H "Authorization: Bearer $SIDESPACE_TOKEN" \
-H "Content-Type: application/json" -d '{"org_id": "'"$ORG"'"}'
curl -X PUT "https://side.example.com/v1/spaces/$SPACE/teams/$TEAM" -H "Authorization: Bearer $SIDESPACE_TOKEN" \
-H "Content-Type: application/json" -d '{"role": "editor"}'Adding someone to a team adds them to the organization as a member if they weren't. Creating an organization takes a person (tokens need the admin scope); giving a team a role in a space takes a space manager (tokens need members:manage).
A member's role in a space
A person's role in a space is the best of their own grant and the roles of their teams there. GET /v1/spaces/{sid}/members shows all three:
{ "user": { "email": "[email protected]" }, "role": "editor", "direct_role": "viewer",
"teams": [{ "id": "team_…", "name": "Editorial", "role": "editor" }] }direct_role is null for someone who is in the space only through teams. Joining or leaving a team changes their role at once. Removing someone from a space while a team still gives them access is refused with 409, naming the team, because "removed" has to mean gone: take them out of the team, or take the team's role away.
Folder access
A folder can carry rules that limit, or widen, what people may change inside it. They never limit what people see.
default_role: the most anyone without a grant may do inside (viewer,commenteroreditor;nullkeeps each person's space role).grants: roles for members of the space (by email) or teams of its organization (by name), which may be above their space role. A viewer can be allowed to upload into one delivery folder.- The nearest folder with rules decides. Rules don't add up across levels, so a folder's rules are read in one place.
- Space managers are never limited, so nobody can lock the space's owner out.
# The edit room may read /final, only Delivery may change it
sidespace access "Film A" /final --default viewer --grant team:Delivery=editor
sidespace access "Film A" /final # your role there, and which folder decides it
sidespace access "Film A" --list # every folder with rules
sidespace access "Film A" /final --clearcurl -X PUT "https://side.example.com/v1/spaces/$SPACE/nodes/$FOLDER/access" \
-H "Authorization: Bearer $SIDESPACE_TOKEN" -H "Content-Type: application/json" \
-d '{"default_role": "viewer", "grants": [{"kind": "team", "name": "Delivery", "role": "editor"}]}'Every write checks the role at its node: creating (at the parent folder), saving a version, renaming and moving (at the node and at the new parent), deleting, restoring, sidecars, renditions, comments (commenter), share links and runs. A refused write is a 403 whose message names the role the folder needs. GET /v1/spaces/{sid}/nodes/{nid}/access returns your role there, your space_role and the rules that decide it (governed_by), so an app can say so before anyone tries; the web app shows "You are viewer here" on such folders and hides what you can't do.
Single sign-on
An organization can sign its people in through its identity provider with OpenID Connect: Okta, Microsoft Entra ID, Google Workspace, Keycloak, Authing and any other provider that publishes /.well-known/openid-configuration. Owners set it up; admins can read it.
- Register the redirect URI with the provider.
GET /v1/orgs/{oid}/ssonames it, and so does its404before single sign-on is set up. - Prove each email domain is yours with a DNS TXT record
_sidespace.<domain>whose value is thedomain_prooffrom the same call (sidespace-verify=…). Without it anyone could claimgmail.com. - Connect the provider for those domains:
sidespace org sso "Harbor Pictures" --issuer https://harbor.okta.com --client-id 0oa… \
--client-secret - --domain harbor.example --required < secret.txt
sidespace org sso "Harbor Pictures" # show it (never the secret)
sidespace org sso "Harbor Pictures" --offcurl -X PUT "https://side.example.com/v1/orgs/$ORG/sso" -H "Authorization: Bearer $SIDESPACE_TOKEN" \
-H "Content-Type: application/json" \
-d '{"issuer": "https://harbor.okta.com", "client_id": "0oa…", "client_secret": "…", "domains": ["harbor.example"], "required": true}'A domain without its TXT record is refused with 422 code domain_unproven. The client secret is sealed with the server's keys and never returned; leave it out of a later PUT to keep it. With required, email codes stop working for those domains. People who sign in through single sign-on join the organization as members.
Signing in from an app
Apps don't handle the provider's tokens. Start a sign-in with the person's address, open the returned url in a browser, and poll with the handle until it answers:
curl -X POST https://side.example.com/v1/auth/sso/start -H "Content-Type: application/json" \
-d '{"email": "[email protected]", "device_name": "Ben’s laptop"}'
# → {"url": "https://harbor.okta.com/…", "handle": "sso_…", "expires_at": "…"}
curl -X POST https://side.example.com/v1/auth/sso/poll -H "Content-Type: application/json" -d '{"handle": "sso_…"}'
# 202 while waiting, 200 with the same tokens as an email sign-in, 410 once expired or collectedstart answers 404 when no organization signs that domain in. When POST /v1/auth/email/start (or verify) answers 403 with code sso_required, switch to this flow. sidespace login EMAIL --sso and the web app's sign-in page do exactly that.
Audit export
Admins can export what happened in the organization, oldest first. Tokens need the admin scope.
sidespace org audit "Harbor Pictures" --since 2026-10-01 --format csv -o audit.csvcurl "https://side.example.com/v1/orgs/$ORG/audit?since=2026-10-01&format=jsonl" -H "Authorization: Bearer $SIDESPACE_TOKEN"Each record has at, source, kind, actor_id, actor_email, and where they apply actor_kind (person, agent or plugin), via (the token or AI action), space_id, space_name, target, path and detail. There are two sources:
org: changes to the organization (people, teams, space roles, folder rules, single sign-on settings) and every single sign-on.space: every file change in the organization's spaces, from their journals, with the file name as it was. A space brought into the organization brings its history.
since and until take RFC 3339 times or dates; the default is the last 30 days. One export returns at most 200 000 records; for more, ask again from the last record's time. In the web app, admins download it from the organization's Audit export tab.