Invitations & collaborators
Two ways to give someone access, and picking the right one is the whole game.
| Organization invitation | Repository invitation | |
|---|---|---|
| Grants | a role across every repository in the org | an access level on one repository |
| Makes them an org member | yes | no |
| They appear in Members | yes | no — in that repository’s Collaborators |
| Right for | teammates | contractors, partners, auditors, another team |
| Endpoint | POST /organizations/{org}/invitations |
POST /repositories/{repoID}/invitations |
Organization invitations
Section titled “Organization invitations”-
Organization settings → Members → Invite.
-
Enter the email and the role (
ADMIN,DEVELOPER,VIEWER,BILLING). See Roles & permissions. -
They get an email with an accept link. Accepting creates their org membership with that role.
export API=https://cavsnode.com/api/v1export H="Authorization: Bearer $CAVS_TOKEN"
curl -sS -X POST "$API/organizations/acme-ai/invitations" \ -H "$H" -H "Content-Type: application/json" \
curl -sS "$API/organizations/acme-ai/invitations" -H "$H" # list pendingcurl -sS -X POST "$API/organizations/acme-ai/invitations/$INV/link" -H "$H" # new linkcurl -sS -X DELETE "$API/organizations/acme-ai/invitations/$INV" -H "$H" # revokeRequires members.invite — ADMIN or OWNER.
Repository invitations (external collaborators)
Section titled “Repository invitations (external collaborators)”This is the interesting one: the invitee does not need to be a member of your organization, and never becomes one. Per-repository access is resolved independently of org membership, so a collaborator row alone is sufficient.
-
Open the repository → Settings → Collaborators → Invite.
-
Enter the email and the access level:
Access They can READpull, browse files, commits, releases WRITEREAD+ push, index, snapshotADMINWRITE+ settings, delete, manage other collaborators -
They accept, and the repository appears under Shared with you in their sidebar. They see nothing else in your organization — not the member list, not other repositories, not billing, not the audit log.
curl -sS -X POST "$API/repositories/$REPO/invitations" \ -H "$H" -H "Content-Type: application/json" \
curl -sS "$API/repositories/$REPO/invitations" -H "$H"curl -sS -X DELETE "$API/repositories/$REPO/invitations/$INV" -H "$H"Requires repository.members.manage — ADMIN/OWNER, or an ADMIN override on
that repository.
Accepting an invitation
Section titled “Accepting an invitation”Two paths, both supported:
The link carries a single-use token. Clicking it signs the person in (creating an account if needed) and accepts:
POST /api/v1/invitations/accept { "token": "<from the link>" }If the email was lost but they can sign in with the invited address, the pending invitation shows up in-app with an Accept button — no token needed. The server enforces that the signed-in email matches the invitation.
GET /api/v1/users/me/invitationsPOST /api/v1/invitations/{invID}/acceptFor a repository invitation the accept response includes repository_id, so the
UI can send them straight to the repository.
Discovering shared access
Section titled “Discovering shared access”curl -sS "$API/users/me/invitations" -H "$H" # pending invitations for mecurl -sS "$API/users/me/shared-repositories" -H "$H" # repos shared with meshared-repositories deliberately excludes repositories in organizations you
belong to — it’s the “someone else’s repository I was given access to” list, which
is what the sidebar’s Shared with you section renders.
Managing existing collaborators
Section titled “Managing existing collaborators”curl -sS "$API/repositories/$REPO/members" -H "$H"
# Grant or change an existing user's accesscurl -sS -X POST "$API/repositories/$REPO/members" \ -H "$H" -H "Content-Type: application/json" \ -d '{"user_id": "…", "access": "WRITE"}'
# Remove accesscurl -sS -X DELETE "$API/repositories/$REPO/members/$USER_ID" -H "$H"The list shows the organization owner (implicitly, and not editable) plus every explicit collaborator row. Organization members whose access comes from their role are not listed — their access is visible in Members, not here.
Revoking
Section titled “Revoking”| To remove | Do |
|---|---|
| A pending invitation | DELETE …/invitations/{invID} |
| An external collaborator | DELETE /repositories/{repoID}/members/{userID} |
| An org member entirely | DELETE /organizations/{org}/members/{userID} |
| Access from one repository only | set their override to NONE |
Revocation takes effect on the next request. There is no automatic revocation of invitations — a revoked invitation was revoked by someone, and the audit log says who.
Regenerating a link
Section titled “Regenerating a link”Settings → Invitations → Copy link on a pending row rotates the token: the new link works, the old one stops. Tokens are stored hashed, so “copy link” can’t show you the original — it mints a fresh one.
Use it when an email bounced or the recipient can’t find it. Send the new link over a channel you trust.
Auditing
Section titled “Auditing”Every step is recorded in the audit log:
member.invited, repository.member.invited, *.invitation.revoked,
*.member.joined, with actor, target and IP.
curl -sS "$API/organizations/acme-ai/audit?limit=100" -H "$H" \ | jq '.events[] | select(.action | test("invit|member"))'- Roles & permissions — what each level grants.
- Organizations & members — the org side.
- Audit log — the record.

