# r*.online Ecosystem — API Reference > Complete endpoint documentation for all modules **Version**: 1.0.0 **Last Updated**: February 2026 --- ## Authentication All modules authenticate via **EncryptID** (WebAuthn passkeys + JWT). ### Token Acquisition ``` POST https://auth.ridentity.online/api/auth/start → { challenge, allowCredentials } POST https://auth.ridentity.online/api/auth/complete ← { token: "eyJ..." } ``` ### Token Transport Attach the JWT to requests using one of: | Method | Format | Use Case | |--------|--------|----------| | Header | `Authorization: Bearer ` | API calls | | Cookie | `encryptid_token=` | Browser navigation | | Query | `?token=` | WebSocket upgrade | | Subprotocol | `Sec-WebSocket-Protocol: encryptid.` | WebSocket upgrade | ### JWT Claims ```json { "sub": "user_abc123", "did": "did:key:z6Mk...", "username": "ana", "authLevel": 2, "aud": ["rspace.online", "rvote.online", "rnotes.online"], "iat": 1708000000, "exp": 1708086400 } ``` ### Auth Levels | Level | Name | Grants | |-------|------|--------| | 1 | BASIC | Read-only operations | | 2 | STANDARD | Create and edit own resources | | 3 | ELEVATED | Moderate other users' resources | | 4 | CRITICAL | Admin operations, key management | --- ## Space Roles & Permissions Every request within a space is authorized against a **SpaceRole**: | Role | Level | Default For | |------|-------|-------------| | VIEWER | 0 | Anonymous users in PUBLIC_READ spaces | | PARTICIPANT | 1 | Anonymous users in PUBLIC spaces, authenticated users in PUBLIC_READ | | MODERATOR | 2 | Explicitly granted | | ADMIN | 3 | Space owner, explicitly granted | ### Checking Capabilities Each module defines a capability map. Example (rVote): ```typescript import { hasCapability, SpaceRole, RVOTE_PERMISSIONS } from '@encryptid/sdk'; // Returns true if user's role meets minimum for capability hasCapability(SpaceRole.PARTICIPANT, 'cast_vote', RVOTE_PERMISSIONS); // true hasCapability(SpaceRole.VIEWER, 'cast_vote', RVOTE_PERMISSIONS); // false ``` --- ## Common Patterns ### Error Responses All modules return errors in this format: ```json { "error": "Not authorized", "code": "FORBIDDEN", "status": 403 } ``` | Status | Meaning | |--------|---------| | 400 | Invalid request body or parameters | | 401 | Missing or invalid authentication token | | 403 | Authenticated but insufficient permissions | | 404 | Resource not found | | 409 | Conflict (duplicate slug, concurrent edit) | | 429 | Rate limited | | 500 | Internal server error | ### Pagination Modules using Prisma support cursor-based pagination: ``` GET /api/proposals?cursor=abc123&take=20 ``` ### Space Scoping Most endpoints are scoped to a space via subdomain: ``` https://crypto.rvote.online/api/proposals → proposals in "crypto" space https://coop.rnotes.online/api/notebooks → notebooks in "coop" space ``` --- ## EncryptID Server **Base URL**: `https://auth.ridentity.online` **Tech**: Hono.js on Bun | PostgreSQL ### Registration | Method | Path | Auth | Description | |--------|------|------|-------------| | POST | `/api/register/start` | None | Begin WebAuthn registration, returns challenge + options | | POST | `/api/register/complete` | None | Complete registration, store credential, return JWT | ### Authentication | Method | Path | Auth | Description | |--------|------|------|-------------| | POST | `/api/auth/start` | None | Begin authentication, returns challenge | | POST | `/api/auth/complete` | None | Complete authentication, return JWT | ### Session Management | Method | Path | Auth | Description | |--------|------|------|-------------| | GET | `/api/session/verify` | Bearer | Verify token validity, returns claims | | POST | `/api/session/verify` | Body | Verify token passed in request body | | POST | `/api/session/refresh` | Bearer | Refresh expired token (1h grace period) | ### Credential Management | Method | Path | Auth | Description | |--------|------|------|-------------| | GET | `/api/user/credentials` | Bearer | List user's registered passkeys | ### Recovery | Method | Path | Auth | Description | |--------|------|------|-------------| | POST | `/api/recovery/email/set` | Bearer | Set recovery email address | | POST | `/api/recovery/email/request` | None | Request recovery email (30-min token) | | POST | `/api/recovery/email/verify` | None | Verify recovery token, issue new session | ### Membership (NEW — Phase 4) | Method | Path | Auth | Description | |--------|------|------|-------------| | POST | `/api/spaces/:slug/members` | Admin | Add or update member in space | | GET | `/api/spaces/:slug/members` | Bearer | List all members of a space | | GET | `/api/spaces/:slug/members/:did` | Bearer | Get one member's role in space | | DELETE | `/api/spaces/:slug/members/:did` | Admin | Remove member from space | --- ## rVote — Decision Engine **Base URL**: `https://{space}.rvote.online` **Tech**: Next.js App Router | PostgreSQL (Prisma) | NextAuth ### Proposals | Method | Path | Auth | Description | |--------|------|------|-------------| | GET | `/api/proposals` | Optional | List proposals (filterable by status) | | POST | `/api/proposals` | PARTICIPANT | Create new proposal | | GET | `/api/proposals/:id` | Optional | Get proposal with vote data | | PATCH | `/api/proposals/:id` | Author | Edit proposal (before voting phase) | | DELETE | `/api/proposals/:id` | Author | Delete proposal (before voting phase) | ### Voting | Method | Path | Auth | Description | |--------|------|------|-------------| | POST | `/api/proposals/:id/vote` | PARTICIPANT | Cast or update ranking vote (spend credits) | | DELETE | `/api/proposals/:id/vote` | PARTICIPANT | Remove vote (refund credits) | | GET | `/api/proposals/:id/final-vote` | Optional | Get final vote counts (YES/NO/ABSTAIN) | | POST | `/api/proposals/:id/final-vote` | PARTICIPANT | Cast final vote on promoted proposal | ### Credits | Method | Path | Auth | Description | |--------|------|------|-------------| | GET | `/api/user/credits` | Bearer | Get user's available and stored credits | | POST | `/api/user/credits` | Bearer | Claim accumulated daily credits | ### Spaces | Method | Path | Auth | Description | |--------|------|------|-------------| | GET | `/api/spaces` | Bearer | List user's spaces | | POST | `/api/spaces` | Bearer | Create new space | | GET | `/api/spaces/:slug` | Optional | Get space details | | PATCH | `/api/spaces/:slug` | ADMIN | Update space settings | | DELETE | `/api/spaces/:slug` | Owner | Delete space | ### Members | Method | Path | Auth | Description | |--------|------|------|-------------| | GET | `/api/spaces/:slug/members` | Bearer | List space members with roles | | POST | `/api/spaces/:slug/members` | ADMIN | Add member by email | | PATCH | `/api/spaces/:slug/members/:userId` | ADMIN | Update member role | | DELETE | `/api/spaces/:slug/members/:userId` | ADMIN | Remove member | ### Invites | Method | Path | Auth | Description | |--------|------|------|-------------| | GET | `/api/spaces/:slug/invites` | ADMIN | List active invite links | | POST | `/api/spaces/:slug/invites` | ADMIN | Create invite link | | DELETE | `/api/spaces/:slug/invites/:id` | ADMIN | Revoke invite link | | GET | `/api/spaces/join/:token` | Bearer | Join space via invite token | --- ## rNotes — Collaborative Notebooks **Base URL**: `https://{space}.rnotes.online` **Tech**: Next.js App Router | PostgreSQL (Prisma) | Automerge CRDT ### Notes | Method | Path | Auth | Description | |--------|------|------|-------------| | GET | `/api/notes` | Bearer | List notes (filter by notebook, type, tags) | | POST | `/api/notes` | PARTICIPANT | Create note | | GET | `/api/notes/:id` | Bearer | Get note with tags | | PATCH | `/api/notes/:id` | Author/MOD | Update note | | DELETE | `/api/notes/:id` | Author/MOD | Delete note | | GET | `/api/notes/search?q=` | Bearer | Full-text search across notes | ### Notebooks | Method | Path | Auth | Description | |--------|------|------|-------------| | GET | `/api/notebooks` | Bearer | List notebooks with note counts | | POST | `/api/notebooks` | PARTICIPANT | Create notebook | | GET | `/api/notebooks/:id` | Bearer | Get notebook details | | PATCH | `/api/notebooks/:id` | Owner/MOD | Update notebook metadata | | DELETE | `/api/notebooks/:id` | Owner/ADMIN | Delete notebook | | GET | `/api/notebooks/:id/notes` | Bearer | Get notes in notebook | | GET | `/api/notebooks/:id/canvas` | Bearer | Get canvas shape data for notebook | ### File Uploads | Method | Path | Auth | Description | |--------|------|------|-------------| | POST | `/api/uploads` | Bearer | Upload file (max 50MB) | | GET | `/api/uploads/:filename` | Bearer | Download file | ### Voice | Method | Path | Auth | Description | |--------|------|------|-------------| | POST | `/api/voice/transcribe` | Bearer | Transcribe audio file | | POST | `/api/voice/diarize` | Bearer | Speaker diarization | ### Canvas Sync | Method | Path | Auth | Description | |--------|------|------|-------------| | POST | `/api/sync` | Service | Receive shape updates from rSpace canvas | --- ## rSpace — Collaborative Canvas **Base URL**: `https://{space}.rspace.online` **Tech**: Hono.js on Bun | Automerge CRDT | WebSocket ### WebSocket Protocol Connect: `wss://{space}.rspace.online/?mode=automerge&token=JWT` | Message Type | Direction | Payload | |--------------|-----------|---------| | `sync` | Bidirectional | Automerge binary sync frame | | `snapshot` | Server→Client | Full JSON state (fallback mode) | | `presence` | Bidirectional | `{ userId, cursor, selection }` | | `ping` | Client→Server | Keep-alive (30s interval) | | `pong` | Server→Client | Keep-alive response | | `error` | Server→Client | `{ code, message }` | ### REST API | Method | Path | Auth | Description | |--------|------|------|-------------| | GET | `/health` | None | Health check with DB connectivity | | GET | `/api/communities/:slug` | Optional | Get community metadata | | POST | `/api/communities/:slug/shapes/:id` | Service | Update shape from module callback | ### Shape Update API (NEW — bidirectional sync) ```json POST /api/communities/{slug}/shapes/{shapeId} Authorization: Bearer { "title": "Updated Note Title", "status": "PASSED", "fields": { ... } } ``` --- ## rCal — Calendar & Scheduling **Base URL**: `https://{space}.rcal.online` **Tech**: Next.js App Router | PostgreSQL (Prisma) ### Events | Method | Path | Auth | Description | |--------|------|------|-------------| | GET | `/api/events` | Optional | List events (filter by date range, source) | | POST | `/api/events` | PARTICIPANT | Create event | | GET | `/api/events/:id` | Optional | Get event details | | PATCH | `/api/events/:id` | Author/MOD | Update event | | DELETE | `/api/events/:id` | Author/MOD | Delete event | ### Calendar Sources | Method | Path | Auth | Description | |--------|------|------|-------------| | GET | `/api/sources` | Bearer | List calendar sources (Google, iCal, etc.) | | POST | `/api/sources` | PARTICIPANT | Add calendar source | | GET | `/api/sources/:id` | Bearer | Get source details | | PATCH | `/api/sources/:id` | Owner | Update source config | | DELETE | `/api/sources/:id` | Owner | Remove source | ### Context & Integration | Method | Path | Auth | Description | |--------|------|------|-------------| | GET | `/api/context/:tool` | Bearer | Get events relevant to an r-tool context | | GET | `/api/lunar` | None | Get lunar phase data for date range | --- ## rMaps — Spatial Intelligence **Base URL**: `https://{space}.rmaps.online` **Tech**: Next.js App Router | PostgreSQL (Prisma) | MapLibre GL ### Routing | Method | Path | Auth | Description | |--------|------|------|-------------| | POST | `/api/routing` | Optional | Calculate route (origin, dest, mode) | Request body: ```json { "origin": { "lat": 52.52, "lng": 13.405 }, "destination": { "lat": 52.51, "lng": 13.39 }, "mode": "walking", "indoor": false } ``` ### Indoor Maps (c3nav) | Method | Path | Auth | Description | |--------|------|------|-------------| | GET | `/api/c3nav/:event` | None | Get indoor map metadata for event | | GET | `/api/c3nav/tiles/:event/:level/:z/:x/:y` | None | Tile server for indoor maps | ### WebSocket (Real-time Location Sharing) Connect: `wss://{room}.rmaps.online/ws?token=JWT` | Message Type | Direction | Payload | |--------------|-----------|---------| | `location` | Client→Server | `{ lat, lng, accuracy, privacy }` | | `locations` | Server→Client | `{ participants: [...] }` | | `waypoint` | Bidirectional | `{ id, name, lat, lng, emoji }` | Privacy modes: `exact`, `approximate`, `area`, `ghost` --- ## rFiles — Secure File Sharing **Base URL**: `https://{space}.rfiles.online` **Tech**: Django REST Framework | PostgreSQL | S3-compatible storage ### Media Files | Method | Path | Auth | Description | |--------|------|------|-------------| | GET | `/api/v1/media/` | Bearer | List files (filter by mime, tags, space) | | POST | `/api/v1/media/` | PARTICIPANT | Upload file | | GET | `/api/v1/media/:id/` | Bearer | Get file metadata | | PATCH | `/api/v1/media/:id/` | Author/MOD | Update metadata | | DELETE | `/api/v1/media/:id/` | Author/ADMIN | Delete file | | POST | `/api/v1/media/:id/share/` | Author | Create share link | | GET | `/api/v1/media/:id/shares/` | Author | List shares for file | | GET | `/api/v1/media/:id/access_logs/` | Author | Access history (last 100) | ### Public Shares | Method | Path | Auth | Description | |--------|------|------|-------------| | GET | `/s/:token/` | None | Download shared file | | GET | `/s/:token/download/` | None | Explicit download | | GET | `/s/:token/info/` | None | Get share info (no download) | | POST | `/s/:token/verify/` | None | Verify password-protected share | ### Share Management | Method | Path | Auth | Description | |--------|------|------|-------------| | GET | `/api/v1/shares/` | Bearer | List user's shares | | POST | `/api/v1/shares/:id/revoke/` | Author | Revoke share link | | POST | `/api/v1/shares/:id/set_password/` | Author | Add password to share | | POST | `/api/v1/shares/:id/remove_password/` | Author | Remove password | ### Direct Upload | Method | Path | Auth | Description | |--------|------|------|-------------| | POST | `/api/upload/` | Bearer | Direct file upload (FormData or pre-signed) | --- ## rFunds — Funding Flows **Base URL**: `https://{space}.rfunds.online` **Tech**: Next.js | React Flow | Automerge CRDT rFunds is primarily client-side (Automerge + localStorage). The flow diagrams are stored in the rSpace Automerge document as `folk-budget` and `demo-expense` shapes. ### Planned Server API | Method | Path | Auth | Description | |--------|------|------|-------------| | POST | `/api/flows` | PARTICIPANT | Save flow diagram to server | | GET | `/api/flows/:id` | VIEWER | Get flow diagram | | POST | `/api/campaigns` | PARTICIPANT | Create crowdfunding campaign | | POST | `/api/campaigns/:id/contribute` | PARTICIPANT | Contribute to campaign | --- ## rTube — Community Video **Base URL**: `https://{space}.rtube.online` **Tech**: Hono.js on Bun | Cloudflare R2 ### Videos | Method | Path | Auth | Description | |--------|------|------|-------------| | POST | `/api/upload` | PARTICIPANT | Upload video file | | GET | `/api/videos` | VIEWER | List videos in space | | GET | `/api/videos/:id` | VIEWER | Get video metadata | | GET | `/api/videos/:id/stream` | VIEWER | Stream video (HTTP range requests) | ### Live Streaming (Planned) | Method | Path | Auth | Description | |--------|------|------|-------------| | POST | `/api/streams` | PARTICIPANT | Start RTMP ingest stream | | GET | `/api/streams/:id/hls` | VIEWER | Get HLS playlist for live stream | --- ## rMail — Secure Messaging **Base URL**: `https://{space}.rmail.online` **Tech**: Next.js App Router | PostgreSQL (Prisma) | IMAP ### Mailboxes | Method | Path | Auth | Description | |--------|------|------|-------------| | GET | `/api/mailboxes` | Bearer | List user's mailboxes | | POST | `/api/mailboxes` | ADMIN | Create mailbox (IMAP/SMTP config) | | GET | `/api/mailboxes/:slug/members` | Bearer | List mailbox members | | POST | `/api/mailboxes/:slug/members` | ADMIN | Add member | | DELETE | `/api/mailboxes/:slug/members/:did` | ADMIN | Remove member | ### Messages | Method | Path | Auth | Description | |--------|------|------|-------------| | GET | `/api/mailboxes/:slug/messages` | Bearer | List messages (IMAP sync) | | GET | `/api/mailboxes/:slug/threads/:threadId` | Bearer | Get email thread | | PATCH | `/api/mailboxes/:slug/threads/:threadId` | Bearer | Update thread (read, folder) | | POST | `/api/mailboxes/:slug/threads/:threadId/comments` | Bearer | Add comment | ### Multi-Sig Approvals | Method | Path | Auth | Description | |--------|------|------|-------------| | GET | `/api/approvals` | Bearer | List pending approvals | | POST | `/api/approvals` | PARTICIPANT | Create email approval draft | | GET | `/api/approvals/:id` | Bearer | Get approval with signatures | | POST | `/api/approvals/:id/sign` | Bearer | Sign approval (add signature) | ### Workspaces | Method | Path | Auth | Description | |--------|------|------|-------------| | GET | `/api/workspaces` | Bearer | List workspaces | | POST | `/api/workspaces` | Bearer | Create workspace | | GET | `/api/workspaces/:slug/mailboxes` | Bearer | List mailboxes in workspace | --- ## rTrips — Trip Planning **Base URL**: `https://{space}.rtrips.online` **Tech**: Next.js App Router | PostgreSQL (Prisma) | Gemini AI ### Trips | Method | Path | Auth | Description | |--------|------|------|-------------| | GET | `/api/trips` | Bearer | List trips | | POST | `/api/trips` | PARTICIPANT | Create trip from parsed text | | GET | `/api/trips/:id` | Bearer | Get trip with all entities | | PATCH | `/api/trips/:id` | Author/MOD | Update trip | | DELETE | `/api/trips/:id` | Author/ADMIN | Delete trip | | GET | `/api/trips/by-slug/:slug` | Bearer | Get trip by slug | | POST | `/api/trips/parse` | Bearer | AI-parse trip text → structured data | ### Destinations | Method | Path | Auth | Description | |--------|------|------|-------------| | GET | `/api/trips/:id/destinations` | Bearer | List destinations | | POST | `/api/trips/:id/destinations` | PARTICIPANT | Add destination | | PATCH | `/api/trips/:id/destinations/:destId` | Author/MOD | Update destination | | DELETE | `/api/trips/:id/destinations/:destId` | Author/MOD | Remove destination | ### Itinerary | Method | Path | Auth | Description | |--------|------|------|-------------| | GET | `/api/trips/:id/itinerary` | Bearer | List itinerary items | | POST | `/api/trips/:id/itinerary` | PARTICIPANT | Add item | | PATCH | `/api/trips/:id/itinerary/:itemId` | Author/MOD | Update item | | DELETE | `/api/trips/:id/itinerary/:itemId` | Author/MOD | Remove item | ### Bookings | Method | Path | Auth | Description | |--------|------|------|-------------| | GET | `/api/trips/:id/bookings` | Bearer | List bookings | | POST | `/api/trips/:id/bookings` | PARTICIPANT | Add booking | | PATCH | `/api/trips/:id/bookings/:bookingId` | Author/MOD | Update booking | | DELETE | `/api/trips/:id/bookings/:bookingId` | Author/MOD | Cancel booking | ### Expenses | Method | Path | Auth | Description | |--------|------|------|-------------| | GET | `/api/trips/:id/expenses` | Bearer | List expenses | | POST | `/api/trips/:id/expenses` | PARTICIPANT | Add expense | | PATCH | `/api/trips/:id/expenses/:expenseId` | Author/MOD | Update expense | | DELETE | `/api/trips/:id/expenses/:expenseId` | Author/MOD | Remove expense | ### Packing Lists | Method | Path | Auth | Description | |--------|------|------|-------------| | GET | `/api/trips/:id/packing` | Bearer | Get packing list | | POST | `/api/trips/:id/packing` | PARTICIPANT | Add item | | PATCH | `/api/trips/:id/packing/:itemId` | Bearer | Check off item | | DELETE | `/api/trips/:id/packing/:itemId` | Author/MOD | Remove item | ### Canvas & Cross-Module | Method | Path | Auth | Description | |--------|------|------|-------------| | GET | `/api/trips/:id/canvas` | Bearer | Get linked canvas shape data | | POST | `/api/trips/:id/sync` | Service | Receive canvas shape updates | | POST | `/api/proxy/rvote` | Bearer | Proxy to rVote (in-trip voting) | | POST | `/api/proxy/rnotes` | Bearer | Proxy to rNotes (shared trip notes) | --- ## rNetwork — Social Graph **Base URL**: `https://{space}.rnetwork.online` **Tech**: Next.js | Automerge CRDT | Force-directed graph rNetwork uses Automerge CRDT for the graph document. No traditional REST API — state syncs via WebSocket. ### WebSocket Protocol Connect: `wss://{space}.rnetwork.online/ws?token=JWT` | Message Type | Direction | Payload | |--------------|-----------|---------| | `sync` | Bidirectional | Automerge binary sync frame | | `snapshot` | Server→Client | Full graph JSON | ### Graph Document Schema ```typescript { meta: { name, slug, visibility, ownerDID }, nodes: { [id]: { type: "person"|"org"|"role", name, metadata } }, edges: { [id]: { source, target, type, label, metadata } } } ``` --- ## rWallet — Treasury **Base URL**: `https://{space}.rwallet.online` **Tech**: Next.js | Gnosis Safe SDK Currently static frontend. Planned API: | Method | Path | Auth | Description | |--------|------|------|-------------| | GET | `/api/safes` | Bearer | List connected Safe wallets | | GET | `/api/safes/:address/balances` | VIEWER | Get token balances | | GET | `/api/safes/:address/transactions` | VIEWER | List transactions | | POST | `/api/safes/:address/propose` | PARTICIPANT | Propose new transaction | | POST | `/api/safes/:address/sign/:txHash` | PARTICIPANT | Sign pending transaction | --- ## EncryptID SDK (npm: `@encryptid/sdk`) ### Client-Side ```typescript import { EncryptIDClient } from '@encryptid/sdk/client'; const client = new EncryptIDClient('https://auth.ridentity.online'); // Register await client.register(username); // Authenticate const { token, claims } = await client.authenticate(); // Share token across r*.online modules await client.shareTokenAcrossModules(token, [ 'rvote.online', 'rnotes.online', 'rmaps.online', ]); ``` ### Server-Side (Hono) ```typescript import { encryptIDAuth, encryptIDSpaceRoleAuth, } from '@encryptid/sdk/server/middleware/hono'; // Simple auth (require valid token) app.use('/api/*', encryptIDAuth({ serverUrl })); // Space + role auth (combined) app.use('/api/*', encryptIDSpaceRoleAuth({ serverUrl, lookupMembership })); // Access context app.get('/api/data', (c) => { const claims = c.get('encryptid'); // EncryptIDClaims const role = c.get('spaceRole'); // ResolvedRole return c.json({ user: claims.did, role: role.role }); }); ``` ### Server-Side (Next.js) ```typescript import { checkSpaceRole, withSpaceRole, } from '@encryptid/sdk/server/middleware/nextjs'; // In a route handler export async function GET(req) { const { claims, role } = await checkSpaceRole(req, { serverUrl: 'https://auth.ridentity.online', spaceSlug: 'crypto', }); if (!hasCapability(role.role, 'view_proposals', RVOTE_PERMISSIONS)) { return Response.json({ error: 'Forbidden' }, { status: 403 }); } // ... handle request } ``` ### Server-Side (Python/Django) ```python from encryptid.roles import SpaceRole, has_capability, RFILES_PERMISSIONS # Check if user can upload files if has_capability(user_role, 'upload_file', RFILES_PERMISSIONS): # allow upload ``` ### Capability Maps Import per-module permission maps: ```typescript import { RVOTE_PERMISSIONS } from '@encryptid/sdk/types/modules'; import { RSPACE_PERMISSIONS } from '@encryptid/sdk/types/modules'; import { RNOTES_PERMISSIONS } from '@encryptid/sdk/types/modules'; import { RFUNDS_PERMISSIONS } from '@encryptid/sdk/types/modules'; import { RMAPS_PERMISSIONS } from '@encryptid/sdk/types/modules'; import { RTUBE_PERMISSIONS } from '@encryptid/sdk/types/modules'; ``` --- ## WebSocket Protocols Summary | Module | URL Pattern | Protocol | Auth | |--------|-------------|----------|------| | rSpace | `wss://{slug}.rspace.online/` | Automerge binary sync | JWT (query/subprotocol) | | rNetwork | `wss://{slug}.rnetwork.online/ws` | Automerge binary sync | JWT (query/subprotocol) | | rMaps | `wss://{room}.rmaps.online/ws` | JSON location/waypoint | JWT (query) | --- ## Cross-Module Integration ### Canvas Shape Sync (module → canvas) When a module updates an entity bound to a canvas shape: ``` POST https://{slug}.rspace.online/api/communities/{slug}/shapes/{shapeId} Authorization: Bearer Content-Type: application/json { "title": "Updated Title", "status": "PASSED" } ``` ### Canvas Shape Sync (canvas → module) When rSpace updates a shape bound to a module entity, it calls the module's sync endpoint: ``` POST https://{slug}.rnotes.online/api/sync POST https://{slug}.rtrips.online/api/trips/{id}/sync ``` ### Module Proxying rTrips demonstrates the proxy pattern for embedded module access: ``` POST /api/proxy/rvote → proxied to rvote.online POST /api/proxy/rnotes → proxied to rnotes.online ```