Organization listing
GET /api/organizations — requires session.
Calls getOrgInstallationsByOrganizationIds from lib/supabase/installation-repository.ts. Returns the user’s organizations plus GitHub App installation status for each.
Organization detail
GET /api/organizations/[login] — requires session + org access.
Calls resolveInstallationForOrganization then InstallationService.getInstallationForOrg. Returns installation metadata for the specified org.
Mass-invite
POST /api/organizations/[login]/mass-invite — requires session + admin + active installation.
Validation pipeline
| Step | Check | Failure |
|---|---|---|
| 1 | Valid session | 401 |
| 2 | login param present | 400 |
| 3 | Valid JSON body | 400 |
| 4 | userLogins is non-empty array of strings | 400 |
| 5 | Trim + deduplicate (case-sensitive Set) + filter empty strings | — |
| 6 | uniqueLogins.length <= 50 | 413 |
| 7 | Admin check (viewerCanAdminister) | 403 |
| 8 | Active installation check | 403 |
Invite execution
Uses installation token (getInstallationOctokit), not user OAuth token.
For each login, two REST calls run simultaneously via Promise.allSettled over all users — there is no batching or concurrency limit constant:
// Step 1 — resolve GitHub database ID
const user = await octokit.rest.users.getByUsername({ username: login });
// Step 2 — send invitation
await octokit.rest.orgs.createInvitation({
org,
invitee_id: user.data.id,
role: 'direct_member', // hardcoded
});Role is always 'direct_member'. There is no option to invite as owner or billing manager through this endpoint.
Response
{
success: string[], // logins that were invited
failed: Array<{ login: string, error: string }>
}Note: the response key is success, not succeeded.
Common failure reasons
'already a member''user not found''invitations disabled''user suspended'
The endpoint is fully synchronous — it blocks until all Promise.allSettled results are back, then returns. There is no background job or queue involved.
Organization summary
GET /api/[org]/organization/summary — requires session + org access.
Queries organizations, teams, and organization_memberships tables via the Supabase admin client.
Response:
{
"repositories": 42,
"teams": 7,
"members": 130
}Teams / members
GET /api/[org]/teams/members — requires session + org access.
Queries teams and team_members tables.
Response:
Array<{
teamSlug: string;
memberCount: number;
}>;Repository analytics
GET /api/[org]/repository/analytics — requires session + org access.
Query params:
| Param | Required | Format |
|---|---|---|
repositorySlug | yes | owner/repo |
from | yes | ISO 8601 date |
to | yes | ISO 8601 date |
Queries the signals table for commits, additions, and deletions grouped by day. Missing repositorySlug → 400.
Response shape: per-day time series with { date, commits, additions, deletions } entries.