Skip to content

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
  1. Organization settings → Members → Invite.

  2. Enter the email and the role (ADMIN, DEVELOPER, VIEWER, BILLING). See Roles & permissions.

  3. They get an email with an accept link. Accepting creates their org membership with that role.

Terminal window
export API=https://cavsnode.com/api/v1
export H="Authorization: Bearer $CAVS_TOKEN"
curl -sS -X POST "$API/organizations/acme-ai/invitations" \
-H "$H" -H "Content-Type: application/json" \
-d '{"email": "[email protected]", "role": "DEVELOPER"}'
curl -sS "$API/organizations/acme-ai/invitations" -H "$H" # list pending
curl -sS -X POST "$API/organizations/acme-ai/invitations/$INV/link" -H "$H" # new link
curl -sS -X DELETE "$API/organizations/acme-ai/invitations/$INV" -H "$H" # revoke

Requires members.inviteADMIN 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.

  1. Open the repository → Settings → Collaborators → Invite.

  2. Enter the email and the access level:

    Access They can
    READ pull, browse files, commits, releases
    WRITE READ + push, index, snapshot
    ADMIN WRITE + settings, delete, manage other collaborators
  3. 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.

Terminal window
curl -sS -X POST "$API/repositories/$REPO/invitations" \
-H "$H" -H "Content-Type: application/json" \
-d '{"email": "[email protected]", "access": "READ"}'
curl -sS "$API/repositories/$REPO/invitations" -H "$H"
curl -sS -X DELETE "$API/repositories/$REPO/invitations/$INV" -H "$H"

Requires repository.members.manageADMIN/OWNER, or an ADMIN override on that repository.

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>" }

For a repository invitation the accept response includes repository_id, so the UI can send them straight to the repository.

Terminal window
curl -sS "$API/users/me/invitations" -H "$H" # pending invitations for me
curl -sS "$API/users/me/shared-repositories" -H "$H" # repos shared with me

shared-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.

Terminal window
curl -sS "$API/repositories/$REPO/members" -H "$H"
# Grant or change an existing user's access
curl -sS -X POST "$API/repositories/$REPO/members" \
-H "$H" -H "Content-Type: application/json" \
-d '{"user_id": "…", "access": "WRITE"}'
# Remove access
curl -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.

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.

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.

Every step is recorded in the audit log: member.invited, repository.member.invited, *.invitation.revoked, *.member.joined, with actor, target and IP.

Terminal window
curl -sS "$API/organizations/acme-ai/audit?limit=100" -H "$H" \
| jq '.events[] | select(.action | test("invit|member"))'