rstack-online/docs/API-REFERENCE.md

25 KiB

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 <token> API calls
Cookie encryptid_token=<token> Browser navigation
Query ?token=<token> WebSocket upgrade
Subprotocol Sec-WebSocket-Protocol: encryptid.<token> WebSocket upgrade

JWT Claims

{
  "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):

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:

{
  "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)

POST /api/communities/{slug}/shapes/{shapeId}
Authorization: Bearer <service-jwt>

{
  "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:

{
  "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

{
  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

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)

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)

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)

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:

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 <service-jwt>
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