One OpsAPI codebase carries every module. Each deployment picks which ones exist with a single environment variable, PROJECT_CODE. A preset name such as business or ecommerce maps to a list of feature flags; several presets can be combined with commas (ecommerce,collaboration), and core is always on.

How a preset decides

PROJECT_CODE decides which route files load and which migrations runPROJECT_CODEe.g. business,cmsper deploymentEnabled featurespresets merged,core always onapp.luaload_if(feature, route)migrations.luaload_if_enabled(...)Routes servedothers answer 404Tables createdothers never exist
Route files for a disabled feature are never loaded, so their URLs answer 404 for everyone, workspace owners and platform admins included, and their tables are never created.

This is the only hard boundary between module sets. Roles inside a workspace can hide a module from a member (403), and the per-workspace menu can hide a page, but neither removes the route. If a tenant must never reach a module, give it its own deployment with a narrower PROJECT_CODE. A code that isn't a preset name is skipped with a warning, so combine preset names, not individual feature names.

Presets at a glance

Which modules each PROJECT_CODE preset switches oncrminvoicingaccountingtax_copilotbank_transactionstimesheetskanbanchatnotificationsecommercedeliveryreviewsshopbillinghospitalfield_serviceacademycmsformsatsthemesvaultservicesmenuallbusinesspropertycollaborationecommerceecommerce_chatfield_servicehospitaltax_copilotbillingacademycmscore_onlyservicesformsats
A filled dot means the preset switches the module on. Every preset also includes core: sign-in, users, workspaces, roles, API keys, webhooks, audit and plugins.

The modules

Module (flag)What it coversExample route
CRM (crm)Accounts, contacts, deals, pipelines, leads, activities/api/v2/crm/…
Invoicing (invoicing)Invoice generation, PDFs and payments/api/v2/invoices
Accounting (accounting)Bookkeeping, VAT returns, trial balance, AI-assisted/api/v2/accounting/accounts
Tax copilot (tax_copilot)UK tax return agent with HMRC MTD filing/api/v2/tax/file
Bank transactions (bank_transactions)Bank transaction tracking/api/v2/bank-transactions
Timesheets (timesheets)Time tracking and approval/api/v2/timesheets
Kanban (kanban)Projects, boards, sprints, tasks, time tracking/api/v2/kanban/…
Chat (chat)Slack-like channels, messages, mentions, reactions/api/chat/channels
Notifications (notifications)Push notifications to devices—
E-commerce (ecommerce)Stores, products, orders, payments/api/v2/stores
Delivery (delivery)Delivery partners, requests and pricing/api/v2/delivery-requests
Reviews (reviews)Product and store reviews—
Shop (shop)Configurable catalogue, carts, quotes, Stripe checkout—
Billing (billing)Apps, flat-tier plans, entitlements, licences/api/v2/billing/plans
Hospital and care (hospital)Hospitals, wards, patients, care plans, medications/api/v2/hospitals
Field service (field_service)Service jobs, phases, sites, engineer visits/api/v2/field-service/jobs
Academy (academy)Courses and lessons with rich content/api/v2/academy/courses
CMS (cms)Website pages and blog: posts, categories, tags, media/api/v2/cms/posts
Forms (forms)Form builder, public forms, responses/api/v2/forms
Hiring (ats)Jobs, candidates, AI first-round interviews/api/v2/ats/…
Themes (themes)Multi-tenant theming/api/v2/themes/…
Vault (vault)Secret vault/api/v2/vault
Services (services)GitHub workflow integration/api/v2/namespace/services/…
Menu (menu)Backend-driven navigation for the dashboard/api/v2/user/menu

Plugins add to this list without forking: a plugin under projects/<name>/ registers its own feature, routes and migrations at boot.

Calling it from TypeScript

@opsapi/client is a typed client for every endpoint, plugins included. A server or script uses an API key scoped to one workspace and the modules it needs:

import { createClient } from '@opsapi/client';

const opsapi = createClient({
  baseUrl: 'https://api.example.com',
  token: process.env.OPSAPI_KEY,   // an API key or a JWT
  namespace: 'acme',               // workspace slug or UUID
});

const { data } = await opsapi.GET('/api/v2/customers', { params: { query: { page: 1 } } });

Keys are created under My Workspace → API Keys or over the API with scopes such as { customers: ['read', 'create'], invoices: ['read'] }. A route for a module your deployment doesn't include still exists in the types, but the server answers 404.