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

# API Reference

> All endpoints organized by controller — method, path, auth requirements, and description.

All endpoints are prefixed with `/api/v1`. All responses use the standard envelope format: `{ "success": true, "data": … }` or `{ "success": false, "error": { "code": "…", "message": "…" } }`.

## Auth `/api/v1/auth`

| Method | Path                   | Auth   | Description                                                                             |
| ------ | ---------------------- | ------ | --------------------------------------------------------------------------------------- |
| POST   | `/register`            | None   | Register a new user. Returns 201, no tokens — user must verify email before logging in. |
| POST   | `/login`               | None   | Login with email and password. Returns access + refresh tokens.                         |
| POST   | `/refresh`             | None   | Exchange a valid refresh token for a new token pair. Old token is revoked.              |
| POST   | `/logout`              | Bearer | Revoke the current refresh token.                                                       |
| GET    | `/verify-email`        | None   | Verify email address with `?token=` query param. Returns token pair on success.         |
| POST   | `/resend-verification` | None   | Resend verification email. Always returns 200 — no email enumeration.                   |
| POST   | `/forgot-password`     | None   | Request a password reset email. Always returns 200 — no email enumeration.              |
| POST   | `/reset-password`      | None   | Reset password with token from email. Revokes all existing refresh tokens.              |
| POST   | `/change-password`     | Bearer | Change password with current password confirmation. Revokes all refresh tokens.         |
| POST   | `/magic-link/request`  | None   | Request a magic link login email. Always returns 200.                                   |
| GET    | `/magic-link/verify`   | None   | Verify magic link with `?token=` query param. Returns token pair.                       |
| GET    | `/me`                  | Bearer | Return the current user's profile and active tenant context.                            |
| GET    | `/google`              | None   | Initiate Google OAuth flow. Redirects to Google.                                        |
| GET    | `/google/callback`     | None   | Google OAuth callback. Redirects to frontend with tokens.                               |
| GET    | `/github`              | None   | Initiate GitHub OAuth flow. Redirects to GitHub.                                        |
| GET    | `/github/callback`     | None   | GitHub OAuth callback. Redirects to frontend with tokens.                               |

## Tenants `/api/v1/tenants`

| Method | Path                             | Auth           | Permission                  | Description                                                                 |
| ------ | -------------------------------- | -------------- | --------------------------- | --------------------------------------------------------------------------- |
| POST   | `/`                              | Bearer         | None                        | Create a new tenant (workspace).                                            |
| GET    | `/mine`                          | Bearer         | None                        | List all tenants the current user belongs to.                               |
| POST   | `/switch`                        | Bearer         | None                        | Switch active tenant. Returns a new token pair with the new tenant context. |
| GET    | `/current`                       | Bearer         | `tenant.settings.read`      | Get current tenant details.                                                 |
| PATCH  | `/current`                       | Bearer         | `tenant.settings.edit`      | Update tenant name or slug.                                                 |
| GET    | `/current/members`               | Bearer         | `tenant.members.read`       | List all members of the current tenant with their roles.                    |
| POST   | `/current/invitations`           | Bearer         | `tenant.members.invite`     | Invite a user to the current tenant by email.                               |
| GET    | `/current/invitations`           | Bearer         | `tenant.members.read`       | List pending and recently expired invitations.                              |
| DELETE | `/current/invitations/{id}`      | Bearer         | `tenant.members.invite`     | Cancel a pending invitation.                                                |
| POST   | `/invitations/accept`            | Bearer or None | None                        | Accept an invitation token. Returns token pair or `REGISTRATION_REQUIRED`.  |
| DELETE | `/current/members/{userId}`      | Bearer         | `tenant.members.remove`     | Remove a member from the tenant. Cannot remove the Owner.                   |
| POST   | `/current/transfer-ownership`    | Bearer         | `tenant.ownership.transfer` | Transfer the Owner role to another member.                                  |
| GET    | `/current/roles`                 | Bearer         | `tenant.roles.read`         | List all roles (built-in and custom) for the tenant.                        |
| POST   | `/current/roles`                 | Bearer         | `tenant.roles.manage`       | Create a custom role.                                                       |
| PUT    | `/current/roles/{roleId}`        | Bearer         | `tenant.roles.manage`       | Update a custom role's name or permissions.                                 |
| DELETE | `/current/roles/{roleId}`        | Bearer         | `tenant.roles.manage`       | Delete a custom role. Fails if members are assigned to it.                  |
| PATCH  | `/current/members/{userId}/role` | Bearer         | `tenant.roles.manage`       | Assign a role to a member.                                                  |

## Billing `/api/v1/billing`

| Method | Path        | Auth   | Permission              | Description                                                                     |
| ------ | ----------- | ------ | ----------------------- | ------------------------------------------------------------------------------- |
| GET    | `/`         | Bearer | `tenant.billing.read`   | Get current tenant's subscription status and plan.                              |
| POST   | `/checkout` | Bearer | `tenant.billing.manage` | Create a Stripe Checkout session for a plan upgrade. Returns `{ checkoutUrl }`. |
| POST   | `/portal`   | Bearer | `tenant.billing.manage` | Create a Stripe Customer Portal session. Returns `{ portalUrl }`.               |

## Users `/api/v1/users`

| Method | Path                   | Auth   | Description                                                             |
| ------ | ---------------------- | ------ | ----------------------------------------------------------------------- |
| GET    | `/profile`             | Bearer | Get the current user's profile (display name, avatar, timezone).        |
| PATCH  | `/profile`             | Bearer | Update display name, avatar URL, or timezone.                           |
| POST   | `/change-email`        | Bearer | Request an email address change. Sends verification to the new address. |
| GET    | `/verify-email-change` | None   | Complete email change with token from email.                            |
| DELETE | `/account`             | Bearer | Delete the current user's account. Requires password confirmation.      |

## Notifications `/api/v1/notifications`

| Method | Path            | Auth   | Description                                                                |
| ------ | --------------- | ------ | -------------------------------------------------------------------------- |
| GET    | `/`             | Bearer | List notifications for the current user in the current tenant. Paginated.  |
| GET    | `/unread-count` | Bearer | Get the unread notification count. Redis-cached, 30-second TTL.            |
| POST   | `/{id}/read`    | Bearer | Mark a single notification as read.                                        |
| POST   | `/read-all`     | Bearer | Mark all notifications as read for the current user in the current tenant. |

## Admin `/api/v1/admin`

All admin endpoints require `is_admin = true` in the JWT claims.

| Method | Path                               | Description                                                                    |
| ------ | ---------------------------------- | ------------------------------------------------------------------------------ |
| GET    | `/users`                           | List all users. Supports `search`, `page`, `pageSize` query params.            |
| GET    | `/tenants`                         | List all tenants. Supports `search`, `page`, `pageSize`.                       |
| GET    | `/tenants/{tenantId}`              | Get tenant detail: members, subscription history, last 20 audit log entries.   |
| GET    | `/subscriptions/overview`          | Aggregate subscription stats: active count, trialing, past due, estimated MRR. |
| POST   | `/users/{userId}/impersonate`      | Issue a JWT for the target user with `impersonator_id` claim.                  |
| PATCH  | `/tenants/{tenantId}/subscription` | Manual subscription status override (local state only, does not touch Stripe). |
| DELETE | `/users/{userId}`                  | Soft-delete a user. Cancels Stripe subscription at period end.                 |

## Webhooks

| Method | Path                      | Auth                    | Description                                                                            |
| ------ | ------------------------- | ----------------------- | -------------------------------------------------------------------------------------- |
| POST   | `/api/v1/webhooks/stripe` | Stripe-Signature header | Receive and process Stripe webhook events. Returns 200 for all events, handled or not. |

## Health

| Method | Path      | Auth | Description                                                            |
| ------ | --------- | ---- | ---------------------------------------------------------------------- |
| GET    | `/health` | None | Returns `{"status":"healthy"}`. Used by load balancers and monitoring. |
