Live API Reference
Documentation of the current WorkSpaceMan API running at api.workshop17.co.za. Built on JXP (jexpress-2) v2.0.0 framework with 88 models.
API Overview
| Base URL | https://api.workshop17.co.za |
| Framework | JXP (jexpress-2) — opinionated API framework generating REST endpoints from Mongoose schemas |
| Version | 2.0.0 |
| Database | MongoDB (via Mongoose ODM) |
| Models | 88 resources |
| Docs | api.workshop17.co.za |
| Source | JXP framework: j-norwood-young/jexpress-2 (GitHub) |
Endpoint Patterns
Every model automatically gets CRUD endpoints following this pattern:
/api/{model} List all (paginated)/api/{model}/{_id} Get single document/count/{model} Count documents/api/{model} Create document/query/{model} Advanced query (MongoDB syntax)/aggregate/{model} Aggregation pipeline/api/{model}/{_id} Update document (acts as PATCH)/api/{model}/{_id} Soft-delete (sets _deleted=true)No PATCH or OPTIONS methods. PUT functions as a partial update. DELETE is a soft-delete (document is flagged, not removed).
Query Parameters
Pagination
| Param | Example | Notes |
|---|---|---|
limit | ?limit=20 | Max documents per page |
page | ?page=2 | Page number (starts at 1) |
Response includes: limit, page_count, page, next for traversal.
Population (Related Objects)
| Param | Example | Notes |
|---|---|---|
autopopulate | ?autopopulate=1 | Expand ALL linked objects |
populate | ?populate=organisation_id | Expand single reference |
populate[] | ?populate[]=organisation_id&populate[]=location_id | Expand multiple |
populate[ref] | ?populate[organisation_id]=name,email | Expand with field selection |
Filtering
| Param | Example | Notes |
|---|---|---|
| Exact match | ?filter[status]=active | Field equals value |
| Greater/less | ?filter[amount]=$gte:1000 | MongoDB operators: $gte, $lte, $gt, $lt, $ne |
| Regex | ?filter[name]=$regex:/tech/i | Case-insensitive pattern match |
Search
| Param | Example | Notes |
|---|---|---|
| Field search | ?search[email]=john | Case-insensitive substring match |
| Full-text | ?search=john | Searches text-indexed fields |
Sorting & Fields
| Param | Example | Notes |
|---|---|---|
sort | ?sort=-createdAt | Prefix - for descending |
fields | ?fields=name,email,status | Return only specified fields |
Response Format
Single Document
{
"data": {
"_id": "60f7b2...",
"name": "James Mokoena",
"email": "james@techflow.co.za",
"organisation_id": "60f7a1...",
"status": "active",
"_deleted": false,
"_owner_id": "60f7b2...",
"createdAt": "2024-01-15T08:30:00Z",
"updatedAt": "2026-03-20T14:22:00Z"
}
}
Collection
{
"count": 342,
"limit": 20,
"page": 1,
"page_count": 18,
"next": "/api/user?page=2&limit=20",
"data": [ ... ]
}
Count
{ "count": 342 }
Returns -1 for collections exceeding 100,000 documents.
Advanced Query
POST /query/invoice
Content-Type: application/json
{
"query": {
"$and": [
{ "status": "AUTHORISED" },
{ "total": { "$gte": 1000 } },
{ "organisation_id": "60f7a1..." }
]
}
}
Aggregation Pipeline
POST /aggregate/ledger
Content-Type: application/json
[
{ "$match": { "user_id": "60f7b2..." } },
{ "$group": {
"_id": "$cred_type",
"total": { "$sum": "$amount" }
}}
]
System Fields (All Models)
Every document includes these fields automatically:
| Field | Type | Notes |
|---|---|---|
_id | ObjectID | Primary key (auto-generated) |
_deleted | Boolean | Soft-delete flag (default: false) |
_owner_id | ObjectID | User who created the document |
_updated_by_id | ObjectID | User who last updated |
createdAt | Date | Immutable creation timestamp |
updatedAt | Date | Last modification timestamp |
__v | Number | Mongoose version key |
All 88 Models
Every model below has auto-generated CRUD endpoints at /api/{name}. Click any model to view its schema on the live API docs.
Core (Members, Spaces, Bookings)
Billing & Financial
CRM & Sales
Infrastructure & Access
Xero & Payments
System & Config
Implications for the New Platform
The live API at api.workshop17.co.za confirms this is the same WorkSpaceMan codebase we reviewed. Key takeaways for the Proximity Green build:
What the JXP Pattern Gets Right
- Auto-generated CRUD — 88 models with zero boilerplate route code. The new platform should replicate this productivity (e.g. Drizzle + auto-generated routes from schema).
- Flexible querying — filter, search, sort, populate, and aggregate all work via query params. The new API should preserve this power.
- Soft deletes —
_deletedflag means data is never lost. The new platform should use the same pattern. - Built-in pagination —
page,limit,nextin every collection response.
What Needs to Change
- No API versioning — a breaking change affects all consumers immediately. New platform must use
/api/v1/. - No input validation — POST/PUT accept any JSON. New platform validates with Zod schemas.
- No rate limiting on the API layer — any authenticated client can hammer endpoints.
- No OpenAPI spec — the docs are generated from Mongoose schemas but aren't in a standard format. New platform generates OpenAPI 3.1.
- MongoDB operators exposed —
$regex,$gte,$andin query params means the API surface is coupled to MongoDB. New platform should abstract this. - No scoped access — an API key has the same access to all 88 models. New platform must scope third-party access per model and operation.
Migration Path
During Phase 6 (migration), the new platform can provide a compatibility layer that accepts the JXP query format and translates to PostgreSQL queries. This allows existing API consumers (if any external integrations exist) to transition gradually.