# CollabSpace — Backend API Reference

## Base URL: `/api/collab`  |  SignalR Hub: `/hubs/collab`
## Auth: All endpoints require Bearer JWT

---

## REST Endpoints

### Sessions
| Method | Endpoint | Body | Response | Notes |
|--------|----------|------|----------|-------|
| POST | `/sessions` | `CreateSessionRequest` | `CollabSession` 201 | Creates and auto-joins host |
| GET | `/sessions/{id}` | — | `CollabSession` | |
| GET | `/sessions/active` | — | `CollabSessionSummary[]` | Sessions user is in |
| GET | `/sessions/scheduled` | — | `CollabSessionSummary[]` | Future scheduled |
| PATCH | `/sessions/{id}/status` | `{ action: 'start'\|'pause'\|'resume'\|'end' }` | `CollabSession` | Host only |
| GET | `/sessions/{id}/join` | — | `JoinSessionResponse` | Adds user as participant |

### Invites
| Method | Endpoint | Body | Response |
|--------|----------|------|----------|
| POST | `/sessions/{id}/invites/users` | `InviteUsersRequest` | 204 |
| POST | `/sessions/{id}/invites/link` | `CreateLinkInviteRequest` | `CollabSessionInvite` |
| GET | `/invites/pending` | — | `CollabSessionInvite[]` |
| POST | `/invites/{token}/join` | — | `JoinSessionResponse` |
| PATCH | `/invites/{id}/respond` | `{ accept: boolean }` | 204 |

### Control
| Method | Endpoint | Body | Response |
|--------|----------|------|----------|
| POST | `/sessions/{id}/control/grant` | `{ targetUserId: string }` | 204 |
| POST | `/sessions/{id}/control/revoke` | — | 204 |

### Config
| Method | Endpoint | Body | Response |
|--------|----------|------|----------|
| GET | `/config` | — | `CollabConfig` |
| PUT | `/config` | `UpdateCollabConfigRequest` | `CollabConfig` |

---

## JoinSessionResponse Shape
```json
{
  "sessionId": "guid",
  "sessionCode": "XK-4291",
  "title": "string",
  "mode": "CoBrowse | ScreenShare | Hybrid",
  "contextRouteUrl": "/ap/invoices/123",
  "yourRole": "Host | Presenter | CoEditor | Viewer",
  "youHaveControl": true,
  "yourCursorColor": "#3182CE",
  "participants": [ ...CollabParticipant[] ],
  "config": { ...CollabConfigClient }
}
```

---

## SignalR Hub — Client → Server Methods
| Method | Parameters |
|--------|-----------|
| `JoinSession` | `sessionId: string` |
| `LeaveSession` | `sessionId: string` |
| `SyncRoute` | `RouteSyncPayload` |
| `SyncCursor` | `CursorPayload` |
| `SyncFormState` | `FormSyncPayload` |
| `RequestControl` | `sessionId: string` |
| `SendChatMessage` | `sessionId: string, text: string` |
| `BroadcastAnnotation` | `AnnotationPayload` |
| `Heartbeat` | `{ sessionId: string, clientTimestamp: number }` |

## SignalR Hub — Server → Client Events
| Event | Payload Type |
|-------|-------------|
| `ParticipantJoined` | `CollabParticipant` |
| `ParticipantLeft` | `{ userId, displayName }` |
| `ControlGranted` | `{ userId, displayName }` |
| `ControlRevoked` | `{ userId }` |
| `ControlRequested` | `{ userId, displayName }` |
| `RouteChanged` | `RouteSyncPayload` |
| `CursorMoved` | `CursorPayload` |
| `FormStateChanged` | `FormSyncPayload` |
| `ChatMessageReceived` | `ChatMessage` |
| `AnnotationReceived` | `AnnotationPayload` |
| `SessionEnded` | `{ reason: string }` |
| `SessionPaused` | `void` |
| `SessionResumed` | `void` |
| `ErrorOccurred` | `{ code: string, message: string }` |

---

## Error Codes
| Code | Meaning |
|------|---------|
| `NOT_IN_SESSION` | Not a participant |
| `SESSION_FULL` | Max participants reached |
| `SESSION_NOT_ACTIVE` | Session not in Active status |
| `UNAUTHORIZED` | Insufficient role |
| `INVITE_EXPIRED` | Token has expired |
| `INVITE_INVALID` | Token not found |
| `INVITE_NOT_FOR_YOU` | Targeted invite for different user |
