REST API Reference
Complete reference for the RootCX Core HTTP API.
Overview
Property
Value
Base URL
https://<your-ref>.rootcx.com (or http://localhost:9100 if self-hosting)
Protocol
HTTP/1.1
Format
JSON (UTF-8)
Max body
50 MB
All /api/v1/* routes accept and return JSON. The deploy endpoint accepts multipart/form-data with an archive field (tar.gz). The logs endpoint returns text/event-stream.
Authentication
Pass a JWT access token as a Bearer token in the Authorization header:
Copy
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
All /api/v1/* endpoints require a valid token except the auth endpoints (register, login, mode). Requests to protected endpoints without a token receive a 401 Unauthorized response.
System
Method
Path
Description
GET
/health
Health check -- returns {status:'ok'}
GET
/api/v1/status
Runtime status (postgres, runtime, forge)
GET /api/v1/status
Copy
{
"runtime" : { "version" : "1.0.0" , "state" : "Online" },
"postgres" : { "state" : "Online" , "port" : 5480 },
"forge" : { "state" : "Offline" , "port" : null }
}
State is one of: Online, Offline, Starting, Stopping, Error.
Auth
Method
Path
Description
POST
/api/v1/auth/register
Register a new user
POST
/api/v1/auth/login
Login and receive tokens
POST
/api/v1/auth/refresh
Refresh an expired access token
POST
/api/v1/auth/logout
Invalidate session
GET
/api/v1/auth/me
Get current authenticated user
GET
/api/v1/auth/mode
Get current auth mode
GET
/api/v1/users
List all users
POST /api/v1/auth/register
Copy
// Request
{
"username" : "alice" ,
"password" : "Str0ngPass!x" ,
"email" : "alice@example.com" , // optional
"display_name" : "Alice Martin" // optional
}
// Response 201
{
"user" : {
"id" : "3fa85f64-5717-4562-b3fc-2c963f66afa6" ,
"username" : "alice" ,
"email" : "alice@example.com" ,
"display_name" : "Alice Martin" ,
"created_at" : "2024-01-15T10:30:00+00:00"
}
}
Password requirements: minimum 10 characters, at least one uppercase letter, one lowercase letter, and one digit.
The first user to register is automatically assigned the admin role on the core app. Registration does not return tokens — call the login endpoint after registration to obtain an access token.
GET /api/v1/auth/mode
Copy
// Response 200
{ "authRequired" : true }
POST /api/v1/auth/login
Copy
// Request
{ "username" : "alice" , "password" : "Str0ngPass!x" }
// Response 200
{
"accessToken" : "eyJ..." ,
"refreshToken" : "eyJ..." ,
"expiresIn" : 900 ,
"user" : {
"id" : "3fa85f64-..." ,
"username" : "alice" ,
"email" : "alice@example.com" ,
"display_name" : "Alice Martin" ,
"created_at" : "2024-01-15T10:30:00+00:00"
}
}
POST /api/v1/auth/refresh
Copy
// Request
{ "refreshToken" : "eyJ..." }
// Response 200
{ "accessToken" : "eyJ..." , "expiresIn" : 900 }
POST /api/v1/auth/logout
Copy
// Request
{ "refreshToken" : "eyJ..." }
// Response 200
{ "message" : "logged out" }
Apps
Method
Path
Description
GET
/api/v1/apps
List all installed applications
POST
/api/v1/apps
Install an application from a manifest
DELETE
/api/v1/apps/{appId}
Uninstall an application
POST /api/v1/apps -- Install app
Copy
// Request body: AppManifest object
{
"appId" : "crm" ,
"name" : "My CRM" ,
"version" : "1.0.0" ,
"dataContract" : [ ... ],
"permissions" : { ... }
}
// Response 200
{
"message" : "app 'crm' installed"
}
[!INFO] Idempotent install
Posting a manifest for an existing app ID triggers a schema sync -- new tables and columns are added, changed types are migrated, and RBAC policies are updated. Existing data is preserved.
Data (CRUD)
Method
Path
Description
GET
/api/v1/apps/{appId}/collections/{entity}
List all records
POST
/api/v1/apps/{appId}/collections/{entity}
Create a record
GET
/api/v1/apps/{appId}/collections/{entity}/{id}
Get a record by ID
PATCH
/api/v1/apps/{appId}/collections/{entity}/{id}
Partially update a record
DELETE
/api/v1/apps/{appId}/collections/{entity}/{id}
Delete a record
Record shape
Copy
{
"id" : "f47ac10b-58cc-4372-a567-0e02b2c3d479" ,
"first_name" : "Alice" ,
"last_name" : "Martin" ,
"email" : "alice@acme.com" ,
"tags" : [ "vip" , "enterprise" ],
"created_at" : "2024-01-15T10:30:00Z" ,
"updated_at" : "2024-01-15T10:30:00Z"
}
Workers
Method
Path
Description
POST
/api/v1/apps/{appId}/deploy
Deploy worker code (multipart, archive field, tar.gz)
POST
/api/v1/apps/{appId}/worker/start
Start the worker process
POST
/api/v1/apps/{appId}/worker/stop
Stop the worker process
GET
/api/v1/apps/{appId}/worker/status
Get worker status
POST
/api/v1/apps/{appId}/rpc
Invoke a worker RPC method
SSE
/api/v1/apps/{appId}/logs
Stream live worker logs
POST /api/v1/apps/{appId}/rpc
Copy
// Request
{
"method" : "sendWelcomeEmail" ,
"params" : { "contactId" : "f47ac10b..." }
}
// Response 200 -- the handler's return value is returned directly
{ "sent" : true }
// Error response
{ "error" : "Failed to connect to SMTP server" }
GET /api/v1/apps/{appId}/worker/status
Copy
{
"app_id" : "crm" ,
"status" : "running"
}
Status is one of: starting, running, stopping, stopped, crashed.
Jobs
Method
Path
Description
POST
/api/v1/apps/{appId}/jobs
Enqueue a background job
GET
/api/v1/apps/{appId}/jobs
List jobs (filter by status)
GET
/api/v1/apps/{appId}/jobs/{jobId}
Get job by ID
POST /api/v1/apps/{appId}/jobs
Copy
// Request
{
"payload" : { "type" : "send_report" , "userId" : "..." }
}
// Response 201
{ "job_id" : "a1b2c3d4-..." }
// Job object (from GET)
{
"id" : "a1b2c3d4-..." ,
"app_id" : "crm" ,
"status" : "completed" ,
"payload" : { "type" : "send_report" , "userId" : "..." },
"result" : { "sent" : true },
"error" : null ,
"attempts" : 1
}
Secrets
Method
Path
Description
POST
/api/v1/apps/{appId}/secrets
Set a secret (idempotent)
GET
/api/v1/apps/{appId}/secrets
List secret key names (not values)
DELETE
/api/v1/apps/{appId}/secrets/{key}
Delete a secret
Copy
// POST /api/v1/apps/crm/secrets
// Request
{ "key" : "OPENAI_API_KEY" , "value" : "sk-..." }
// Response
{ "message" : "secret 'OPENAI_API_KEY' set" }
// GET /api/v1/apps/crm/secrets
// Response -- key names only, never values
[ "OPENAI_API_KEY" , "STRIPE_SECRET_KEY" , "SMTP_PASSWORD" ]
Method
Path
Description
POST
/api/v1/platform/secrets
Set a platform-wide secret
GET
/api/v1/platform/secrets
List platform secret key names
DELETE
/api/v1/platform/secrets/{key}
Delete a platform secret
Platform secrets are shared across integrations. App-level secrets (above) are scoped to a single app.
RBAC
Method
Path
Description
GET
/api/v1/apps/{appId}/roles
List all roles
POST
/api/v1/apps/{appId}/roles
Create a role
PATCH
/api/v1/apps/{appId}/roles/{roleName}
Update a role
DELETE
/api/v1/apps/{appId}/roles/{roleName}
Delete a role
GET
/api/v1/apps/{appId}/roles/assignments
List user-role assignments
POST
/api/v1/apps/{appId}/roles/assign
Assign a role to a user
POST
/api/v1/apps/{appId}/roles/revoke
Revoke a role from a user
GET
/api/v1/apps/{appId}/permissions
Current user's effective permissions
GET
/api/v1/apps/{appId}/permissions/available
List all available permission keys
GET
/api/v1/apps/{appId}/permissions/{userId}
Specific user's permissions
Copy
// POST /api/v1/apps/crm/roles/assign
{ "userId" : "3fa85f64-..." , "role" : "admin" }
// GET /api/v1/apps/crm/permissions
{
"roles" : [ "admin" ],
"permissions" : [ "contacts.create" , "contacts.read" , "contacts.update" , "contacts.delete" , "deals.create" , "deals.read" , "deals.update" , "deals.delete" ]
}
Audit
Method
Path
Description
GET
/api/v1/audit
Query the audit log
Copy
# Query parameters
$ GET /api/v1/audit
?app_id =crm # Filter by app (matches table_schema)
&entity = contacts # Filter by table name
&limit = 100 # Max results (default 100, max 1000)
Copy
[
{
"id" : 1001 ,
"table_schema" : "crm" ,
"table_name" : "contacts" ,
"record_id" : "f47ac10b-..." ,
"operation" : "UPDATE" ,
"old_record" : { "email" : "alice@old.com" },
"new_record" : { "email" : "alice@acme.com" },
"changed_at" : "2024-01-15T10:30:00Z"
}
]
All errors return a JSON body with an error field and the appropriate HTTP status code:
Copy
{ "error" : "human-readable error message" }
Status
Meaning
Common causes
400
Bad Request
Invalid JSON, missing required fields, validation error, duplicate username/app ID
401
Unauthorized
Missing or invalid Bearer token
403
Forbidden
Valid token but RBAC policy denies the action
404
Not Found
Record doesn't exist or you don't have ownership access
500
Internal Server Error
Unexpected database or runtime error
503
Service Unavailable
PostgreSQL or daemon not ready yet