> ## Documentation Index
> Fetch the complete documentation index at: https://docs.zappway.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Memberships API

> Internal reference for the Memberships API — member CRUD, invitation management, role/group changes, and access control enforcement.

> **Internal documentation for developers.** This page covers the Memberships API: team member management, access group assignment, and invitation lifecycle. Not intended for end users.

***

## Route Map

| Method   | Endpoint                | Handler File                | Description         |
| -------- | ----------------------- | --------------------------- | ------------------- |
| `GET`    | `/api/memberships`      | `memberships/route.ts`      | List org members    |
| `POST`   | `/api/memberships`      | `memberships/route.ts`      | Invite a new member |
| `GET`    | `/api/memberships/[id]` | `memberships/[id]/route.ts` | Get member by ID    |
| `PATCH`  | `/api/memberships/[id]` | `memberships/[id]/route.ts` | Update role/group   |
| `DELETE` | `/api/memberships/[id]` | `memberships/[id]/route.ts` | Remove member       |

***

## Auth Pattern

```ts theme={null}
withPermissionRoute(req, {
  permission: 'team.read',    // reads
  permission: 'team.invite',  // invitations
  permission: 'team.manage',  // updates, removals
}, handler)
```

***

## Membership Object Schema

```ts theme={null}
interface Membership {
  id: string;
  organizationId: string;
  userId: string;
  user: { id: string; name: string; email: string; };
  role: 'admin' | 'member';
  status: 'active' | 'invited' | 'suspended';
  accessGroupIds: string[];
  invitedAt: string | null;
  joinedAt: string | null;
  createdAt: string;
}
```

***

## Invitation Lifecycle

```
1. Admin: POST /api/memberships { email, accessGroupId }
   → status: 'invited', invitedAt = now()
   → Email sent with invite link

2. Invitee clicks link → GET /api/auth/invite?token=...
   → status: 'active', joinedAt = now()
   → User created (if first login)

3. Admin: DELETE /api/memberships/[id]
   → Removes membership (cascade: removes from access groups)
   → User loses org access immediately
```

***

## Access Group Assignment

When updating a member (`PATCH /api/memberships/[id]`):

```ts theme={null}
// Body: { accessGroupIds: string[] }
// This REPLACES the member's group assignments entirely
// Validates all group IDs belong to the same organization
// Records change in permission audit log
```

***

## Self-Remove Prevention

Members cannot remove themselves. The server checks:

```ts theme={null}
if (membershipToDelete.userId === req.session.user.id) {
  return NextResponse.json({ error: 'Cannot remove yourself' }, { status: 403 });
}
```

***

## Known Issues / Gotchas

* **Last admin protection:** Orgs must always have at least one admin. Attempting to remove the last admin returns `403`.
* **Suspended status:** Not fully implemented in all flows — treated as `active` in some legacy code paths. Verify before using `suspended` status in new features.
* **Permission cache:** Permissions are cached in the session. After changing a member's access group, they must log out and back in for changes to take effect in existing sessions.
