Skip to content

Organizations, members, and invitations ​

An organization owns apps and controls who can manage them. Use an organization ID in API paths; its slug is used in public URLs and when confirming deletion. All routes on this page use a GitHub dashboard session cookie. API tokens cannot create organizations, manage members, or send invitations.

The examples assume RD_URL=https://releases.example.com and a signed-in browser session. If you call these routes from a script, send that session cookie; an Authorization: Bearer rd_... header is not enough. See Authentication and access for the difference.

Organizations ​

Method and pathMinimum roleSuccessPurpose
GET /api/v1/orgsSigned-in user200List organizations the user belongs to
POST /api/v1/orgsSigned-in user201Create an organization and become its owner
PATCH /api/v1/orgs/:orgIdOwner200Change the name and slug
DELETE /api/v1/orgs/:orgIdOwner204Delete the organization and its data

GET /api/v1/orgs returns { "items": [...] }. Each item contains id, name, slug, and the caller's role. There is no standalone GET /api/v1/orgs/:orgId route; use the list to obtain an ID.

Create an organization with a name and slug:

http
POST /api/v1/orgs
Content-Type: application/json

{"name":"Northstar Apps","slug":"northstar-apps"}

The response is an object such as {"id":"org_...","name":"Northstar Apps","slug":"northstar-apps","role":"owner"}. Names and slugs must be 1–100 characters. Slugs use lowercase letters, digits, and internal hyphens. A slug already used on this server returns 409 org_slug_taken.

Updating an organization requires both name and slug, even if only one changes:

http
PATCH /api/v1/orgs/org_123
Content-Type: application/json

{"name":"Northstar Software","slug":"northstar-apps"}

The response contains the updated id, name, and slug. Changing the slug changes the organization's public download page paths. Check links you have published before changing it.

Deletion requires the current slug as confirmation:

http
DELETE /api/v1/orgs/org_123
Content-Type: application/json

{"confirmSlug":"northstar-apps"}

The server deletes the organization's database records, including its apps and releases, then attempts to remove stored artifact files. A mismatched confirmation returns 400 validation_failed. Deletion cannot be undone through this API; keep a backup before using it.

Members ​

Method and pathMinimum roleSuccessPurpose
GET /api/v1/orgs/:orgId/membersViewer200List members
PATCH /api/v1/orgs/:orgId/members/:userIdAdmin200Set a member's role
DELETE /api/v1/orgs/:orgId/members/:userIdAdmin204Remove a member

The list returns { "items": [...] }. A member includes userId, orgId, role, source, githubLogin, name, and avatarUrl. source tells you whether membership was added manually or through GitHub organization synchronization. Use userId from this list for role changes; a GitHub login is not the path parameter.

To change a role, send one of viewer, developer, admin, or owner:

http
PATCH /api/v1/orgs/org_123/members/user_456
Content-Type: application/json

{"role":"developer"}

The response is the updated member object. A role change sets the membership source to manual. The last owner cannot be demoted or removed (403 forbidden), and an owner cannot remove themselves with this endpoint. Transfer ownership first if the current owner needs to leave. Removing someone who has no remaining organization memberships revokes their dashboard sessions, unless they are the instance owner.

The following routes use /api/v1/orgs/:orgId/logo and require a dashboard session. GET requires a viewer role and returns the image bytes. PUT and DELETE require the owner role; PUT accepts raw PNG, JPEG, or WebP bytes, at most 512 KiB, and returns the updated organization. DELETE removes the logo and returns the updated organization. An absent logo returns 404 on GET.

An organization can synchronize members from a GitHub organization. GET /api/v1/orgs/:orgId/github-link requires admin and returns the saved link with its team roles, or JSON null when no link exists. PUT requires owner and replaces the link configuration:

http
PUT /api/v1/orgs/org_123/github-link
Content-Type: application/json

{
  "githubOrgLogin": "northstar",
  "defaultRole": "viewer",
  "teamRoles": [
    {"teamSlug":"release-engineering","role":"developer"}
  ]
}

githubOrgLogin and each teamSlug must be nonempty. defaultRole and team roles use the same four roles as member management. Omit teamRoles for an empty mapping. The response is the stored link. A later PUT replaces the team mappings; include every mapping you want to retain. See Authentication and access for when membership synchronization runs.

Invitations ​

Method and pathMinimum roleSuccessPurpose
GET /api/v1/orgs/:orgId/invitesAdmin200List pending invitations
POST /api/v1/orgs/:orgId/invitesAdmin201Email an invitation
DELETE /api/v1/orgs/:orgId/invites/:inviteIdAdmin204Revoke a pending invitation
GET /api/v1/invites/:tokenInvitation token200Preview an invitation
POST /api/v1/invites/:token/acceptInvitation token and GitHub session200Accept it

To invite someone, send their email and proposed role:

http
POST /api/v1/orgs/org_123/invites
Content-Type: application/json

{"email":"dev@example.com","role":"developer"}

Only an owner may invite another owner. The server queues an email with a link; the API response does not expose the invitation token. It returns the invitation id, email, role, invitedBy, createdAt, and expiresAt. Pending invitations expire after seven days. Sending a new invitation to the same address replaces its earlier pending invitation. Inviting an existing member returns 409 invite_conflict.

The invitation URL contains a token. Its preview route returns orgName, role, and email without a dashboard session. The recipient then signs in with GitHub and calls the accept route. The signed-in account's email must match the invited address; otherwise acceptance returns 403 invite_invalid. Acceptance returns { "orgId": "org_..." }. Invalid, expired, accepted, or revoked tokens return 404 invite_not_found.

Common failures ​

An unknown organization or one the caller does not belong to returns 404 org_not_found. A known member with an insufficient role gets 403 forbidden. Missing dashboard authentication returns 401 unauthorized. Malformed JSON fields fail route validation with 400; see API conventions for the validator's response shape.